概述
理论:
所谓SMC(Self Modifying Code)技术,就是一种将可执行文件中的代码或数据进行加密,防止别人使用逆向工程工具对程序进行静态分析的方法,只有程序运行时才对代码和数据进行解 密,从而正常运行程序和访问数据。本篇通过一个简单的实例来介绍这个技术。 需要的运行环境vc6,程序编译为release版。由于本篇我们要在程序执行过程中,修改代码段中的一个函数内容,而默认情况下,我们编译生成的程序代码段是可读可执行属性。所以我们需要使用一个预编译指令。
#pragma comment(linker, “/SECTION:.text,ERW”)
是告诉链接程序最终在生成代码时修改这个名为”.text” 的代码段,段 属性为”ERW”,分别表示可执行、可读和可写。当然你也可以不使用预编译指令#pragma comment,直接在编译选项中添加”/SECTION:.text,ERW”选项也可以达到相同的目的。
所谓SMC(Self Modifying Code)技术,就是一种将可执行文件中的代码或数据进行加密,防止别人使用逆向工程工具对程序进行静态分析的方法,只有程序运行时才对代码和数据进行解 密,从而正常运行程序和访问数据。本篇通过一个简单的实例来介绍这个技术。 需要的运行环境vc6,程序编译为release版。由于本篇我们要在程序执行过程中,修改代码段中的一个函数内容,而默认情况下,我们编译生成的程序代码段是可读可执行属性。所以我们需要使用一个预编译指令。
#pragma comment(linker, “/SECTION:.text,ERW”)
是告诉链接程序最终在生成代码时修改这个名为”.text” 的代码段,段 属性为”ERW”,分别表示可执行、可读和可写。当然你也可以不使用预编译指令#pragma comment,直接在编译选项中添加”/SECTION:.text,ERW”选项也可以达到相同的目的。
#include "windows.h" #pragma comment(linker, "/SECTION:.text,ERW") int lnth1; char szDlgTitle[] = "SMC example"; char Phony[] = "This is lst call of proc"; char Replc[] = "This is 2nd call of proc"; char ttl1[] = "Original Code"; char ttl2[] = "ReplaceMent Code"; void CalledProc(); void EndCalledProc(); void RepalceMentProc(); void EndRepalceMentProc(); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. CalledProc(); int lnth1 = (char *)EndRepalceMentProc - (char *)RepalceMentProc; memcpy((char *)CalledProc,(char *)RepalceMentProc,lnth1); CalledProc(); return 0; } void CalledProc() { MessageBox(0,Phony,ttl1,MB_OK); } void EndCalledProc() { } void RepalceMentProc() { MessageBox(0,Replc,ttl2,MB_OK|MB_ICONEXCLAMATION); } void EndRepalceMentProc() { }
分析:
本例中,我们先执行了CalledProc函数,显示出一个MESSAGEBOX. 然后,我们用RepalceMentProc函数的内容,在运行过程中修改CalledProc函数,在C语言中,函数名代表函数的首地址,为了计算函数体的长度,我们在函数后面定义了一个空函数,通过下面这样的公式,来大致的计算函数体的长度。主要原因是函数之间还有空隙。
int lnth1 = (char *)EndRepalceMentProc - (char *)RepalceMentProc;
由于代码段属性是可写的,因此,我们在这里通过下面的代码
memcpy((char *)CalledProc,(char *)RepalceMentProc,lnth1);
使用RepalceMentProc函数体中的机器码替换了CalledProc函数中原有的机器码。
这样再次调用CalledProc的时候,实际就执行的是RepalceMentProc函数的代码了。
本例中,我们先执行了CalledProc函数,显示出一个MESSAGEBOX. 然后,我们用RepalceMentProc函数的内容,在运行过程中修改CalledProc函数,在C语言中,函数名代表函数的首地址,为了计算函数体的长度,我们在函数后面定义了一个空函数,通过下面这样的公式,来大致的计算函数体的长度。主要原因是函数之间还有空隙。
int lnth1 = (char *)EndRepalceMentProc - (char *)RepalceMentProc;
由于代码段属性是可写的,因此,我们在这里通过下面的代码
memcpy((char *)CalledProc,(char *)RepalceMentProc,lnth1);
使用RepalceMentProc函数体中的机器码替换了CalledProc函数中原有的机器码。
这样再次调用CalledProc的时候,实际就执行的是RepalceMentProc函数的代码了。
注意:
篇文章与实际应用还是有很大的距离的,RepalceMentProc的长度不能比CalledProc();长的太多,虽然在中间补了EndCalledProc,但也不能太长。可不可把修改的代码放到堆上,然后将CalledProc的地址改过去
最后
以上就是舒心柠檬为你收集整理的程序自修改(SMC)的全部内容,希望文章能够帮你解决程序自修改(SMC)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复