C++ 更改C+中定义的数字+;(C) 不重新编译源代码的程序

C++ 更改C+中定义的数字+;(C) 不重新编译源代码的程序,c++,windows,C++,Windows,假设我有一个打印数字的简单程序: #include <iostream> int unique_id = 112233; int main() { std::cout << unique_id; return 0; } #包括 int unique_id=112233; int main() { STD::CUT< P>不,改变一个变量的行为,即 const 是未定义的。因此,不能用标准C或C++来执行。 您最好使用内联汇编解决方案;但是注意,代码> >

假设我有一个打印数字的简单程序:

#include <iostream>
int unique_id = 112233;
int main()
{
    std::cout << unique_id;
    return 0;
}
#包括
int unique_id=112233;
int main()
{

STD::CUT< P>不,改变一个变量的行为,即<代码> const 是未定义的。因此,不能用标准C或C++来执行。

<>您最好使用内联汇编解决方案;但是注意,代码> > UNQuiGIDID/CODE >可以全部编译(C和C++都不是反射语言)。为了增加代码< UNQuiGID ID/COD>保留的可能性,删除<代码> const <代码>限定符,并可能引入<代码>易失性< /代码> .< 我个人会将命令行上的
UNIQUE\u ID
传递给您的程序


起始点:

不,改变一个变量的行为是<代码> const < /C> >未定义。因此,不能用标准C或C++来做。

<>您最好使用内联汇编解决方案;但是注意,代码> > UNQuiGIDID/CODE >可以全部编译(C和C++都不是反射语言)。为了增加代码< UNQuiGID ID/COD>保留的可能性,删除<代码> const <代码>限定符,并可能引入<代码>易失性< /代码> .< 我个人会将命令行上的
UNIQUE\u ID
传递给您的程序


起点:

通常,不重新编译就无法更改任何内容

实际上,在非常有限的情况下,您可能会修补二进制文件。这主要是特定于处理器的(以及特定于可执行格式和ABI的),并且不太依赖于您的特定操作系统版本(例如,如果它适用于Windows 9,则可能适用于Windows 10)

(然而,我不知道也从未使用过Windows;我只使用Linux;您应该根据您的操作系统调整我的答案)

因此,在某些情况下,您可能会对二进制可执行文件进行反向工程。如果您有C源代码,您可以要求编译器发出汇编代码(例如,通过使用
gcc-O-fverbose asm-S
with进行编译)。然后您可以反汇编可执行文件,并使用二进制或十六进制编辑器更改包含该常量的机器代码

这并不总是有效的,因为机器指令(及其大小)可能取决于常量的大小(位大小)

举一个简单的例子,在C中,对于GCC 7,在Linux /X8664上,考虑下面的C文件:

 /// A, B, C are preprocessor symbols defined as integers
 int f(int x) { 
   if (x > 0)
     return A*x + B;
   return C;
 }
如果我用gcc-fverbose asm-S-O-DA=12751-DB=32-DC=11 e.c编译它,我得到:

    .type   f, @function
f:
.LFB0:
    .cfi_startproc
# e.c:3:   if (x > 0)
    testl   %edi, %edi  # x
    jle .L3 #,
# e.c:4:     return A * x + B;
    imull   $12751, %edi, %edi  #, x, tmp90
    leal    32(%rdi), %eax  #, <retval>
    ret
.L3:
# e.c:5:   return C;
    movl    $11, %eax   #, <retval>
# e.c:6: }
    ret
    .cfi_endproc
.LFE0:
    .size   f, .-f
因此,实际上,在上述情况下,我可以修补二进制文件(我需要在机器代码中找到
12751
11
常量;在这种情况下,这是可行的,但很乏味)


现在,让我们试试A是2的小幂,比如16,C是0,所以
gcc-S-O-fverbose asm-DA=16-DB=32-DC=0 e.c

f:
.LFB0:
    .cfi_startproc
# e.c:4:     return A * x + B;
    leal    2(%rdi), %eax   #, tmp90
    sall    $4, %eax    #, tmp93
    testl   %edi, %edi  # x
    movl    $0, %edx    #, tmp92
    cmovle  %edx, %eax  # tmp93,, tmp92, <retval>
# e.c:6: }
    ret
f:
.LFB0:
.cfi_startproc
#e.c:4:返回A*x+B;
leal 2(%rdi),%eax#,tmp90
全部4美元,eax#,tmp93
testl%edi,%edi#x
movl$0,%edx#,tmp92
cmovle%edx,%eax#tmp93,,tmp92,
#e.c:6:}
ret
由于编译器的优化,代码发生了显著的变化。这不容易修补

重要通知 只要付出足够的努力、金钱和时间(想想NSA一样的能力),很多事情都是可能的

如果您的目标是混淆二进制文件中的某些数据(例如某些密码),您可能会对其进行加密,以使黑客的生活更加困难(但不要天真,NSA将能够获得它)。记住这句格言:有;看起来这是你的目标,但不要太天真(顺便说一句,你的软件周围的法律保护,例如许可证,更重要;因此你需要一位律师来撰写一份好的EULA)

如果您的目标与此相反,是适应一些性能关键的代码,那么您可以使用和技术。我喜欢做的一个练习是在运行时生成一些临时的C(或C++)代码(更适合于你的特定情况和数据),编译临时C或C++代码,然后使用临时插件(Linux上使用和Linux;你需要Windows代码< LoadLibrary >代码>,但是我让你了解细节和后果)。而不是在运行时生成C或C++代码,可以使用一些类似的库。如果你喜欢这样的技术,你可以考虑使用更好的编程语言(如通用LISP),如果你的管理允许的话。 但我不想为1000个客户编译1000次我的程序

这让我很惊讶。编译一个只包含常量的简单(短)C文件很快,链接时间也很快。我会考虑为每个客户重新编译。

顺便说一句,我觉得你太天真了。在你的二进制文件中,最重要的保护不是技术性的,而是法律性的保护(你需要一份好的合同,所以找一个好的律师并付钱)

你是不是考虑把产品变成免费软件?许多公司都在这样做(并在其他许可的东西上赚钱,例如支持)



注意。有很多现有的。你考虑购买和使用吗?还要注意的是,公司有很大的动机来避免作弊,而那些愿意窃取你的软件的人无论如何也能做到这一点。通过提高软件质量,而不是在烦扰客户的徒劳的“保护”措施上花费精力,增加您的软件开发、分发和维护成本,并加强对客户发现的bug的调试,您将销售更多的产品。

一般来说,不重新编译,您无法更改任何内容

实际上,在非常有限的情况下,您可能会修补二进制文件。这主要是特定于处理器的(以及特定于可执行格式和ABI的),较少依赖于您的特定操作系统版本(例如,如果它适用于Windows 9,则可能适用于Windows 10)

(然而,我不知道
f:
.LFB0:
    .cfi_startproc
# e.c:4:     return A * x + B;
    leal    2(%rdi), %eax   #, tmp90
    sall    $4, %eax    #, tmp93
    testl   %edi, %edi  # x
    movl    $0, %edx    #, tmp92
    cmovle  %edx, %eax  # tmp93,, tmp92, <retval>
# e.c:6: }
    ret