EXE注入函数完整过程及分析总结(图15个,含函数重定向,参数即变量,不是运行时注入函数,是在EXE文件中注入,有计算公式及总结)
## EXE注入函数完整过程及分析总结(图15个,含函数重定向,参数即变量,不是运行时注入函数,是在EXE文件中注入,有计算公式及总结)
把微软红星大战游戏heart.exe,拷贝为D.EXE。修改原EXE文件运行后(不是运行时注入,是EXE文件注入),先弹出自己的一个对话框,然后正常游戏。几乎花了2周的时间,从头到尾。这只是后面一部分。涉及到DLL函数重定位,函数参数即变量的相对地址,PE文件的结构。声明一下,在WIN 7 32位 + Intel 赛扬上破解注入成功的。
关于 函数地址的重定位,网上很多,我看了很多只是看了个大概,有点模糊。而关于参数(变量)地址的重定位,则在网上没有找到。我自己尝试分析了很久,最后终于把这2个问题搞清楚了。
本人信奉动手做,只说不做不大喜欢。实现这个破解和注入,过程很辛苦,但也有收获,愿和同行互相交流。
0. 关于EXE函数地址的重定位和参数(变量)地址的重定位问题分析
地址重定位,就是保证EXE文件加载到内存后,能正确寻址到对应地址。
(1) EXE文件加载到内存后,有一个地址,这个内存运行地址叫“虚地址”即VirtualAddress, 而我们EXE文件中的地址是“文件地址“即PointerToRawData。
(2)不论是 EXE原文件, 还是加载到内存后准备执行,都要分段的, 这就是“段”的概念。数据段.data,代码段.text,重定位段.reloc,只读数据段.rsrc
(3)每个EXE在加载到内存后,都有一个开始地址。每次这个地址不确定,这个地址是虚地址。这就需要对EXE中的所有地址在加载时,重新定位(更改)地址。
而每个EXE文件,都有一个默认的虚地址。我们以这个程序的基准地址,保证重定位正确即可。
每个段(数据段.data,代码段.text,重定位段.reloc,只读数据段.rsrc)在装入入内存后,也有一个相对虚地址,这个地址就是段的相对偏移虚地址。
程序的基准地址 + 段的相对偏移虚地址, 就是我们往常说的寄存器段址。
(4)每个WINDOWS API函数有一个固定的地址,这个地址在保存在内存中。不同的EXE,这个保存地址是不同的。例如上面这个EXE文件的MessageBoxW地址就保存在01 00 14 01 H这个位置。这个地址是由编译程序决定的。
( 5 )现在说 API 函数的重定位问题。
先看这条命令:
8 A120 H: CALL user32.MessageBoxW ;对应的汇编语言在我们的例子中是
8 A120 H: FF 01 14 00 01
这里就需要对位置8 A122 H中的地址 01 14 00 01(即01001401)进行重定位。其中8 A122 H是文件地址,我们需要计算它对应的内存地址即虚地址。
因为整个程序加载到内存的虚地址是 100 0000 H(API 函数重定位不考虑这个,下面忽略)。 代码段TEXT加载到内存的虚地址是 1000 H,即TEXT段的虚地址是100 1000 H。这是运行情况(API 函数重定位只考虑1000 H)。
再看EXE文件情况。在EXE文件中,TEXT段的开始地址是600 H。而我们需要重定位函数的文件地址是8 A122 H。所以相对位置是8A122 H – 600 H = 8 9B22 H.
综上2方面的情况,我们需要输入的重定位函数虚地址是
1000 H + 8 9B22 H = 8 AB22 H, 就是重定位表中的一项。
因为现有重定位表中,没有与8 AB22 H接近的条目,所以我们增加了一个条目(如何增加条目,此处省略)。我们这里增加的是8 A000 H 这个条目。
在这个条目下,增加重定位项: 8 AB22 H – 8A000 H = B22 H
但别忘记了, WINDOW要求再加 3000 H, 即B22 H + 3000 H = 3B22 H
最后,输入的重定位项数据是 3B22 H
(6 )最后说 API 函数参数的重定位问题。
我们这里函数用到2个参数,这2个字符串的文件存储地址是9 2BBOH, 92BDOH (4个文字串,我们只用2个)。
只说9 2BBOH这个参数如何重定位,另一个参数的地址重定位同理。
EXE文件的数据段DATA地址是 8 A200 H, 而我们要定位的参数是 9 2BBOH。相对位置是 9 2BBOH – 8 A200 H = 89B0 H.
整个程序加载到内存的虚地址是 100 0000 H, 数据段DATA加载到内存的虚地址是8 B000 H,所以数据段DATA最后加载的虚地址是108 B000 H。
综上2方面的情况,我们需要输入的重定位参数虚地址是
108 B000 H + 89B0 H. = 109 39B0 H
注意,参数重定位时,要考虑程序的虚地址 100 0000 H,而函数地址重定位不考虑它,因为最后要保证程序正确执行的;
函数地址重定位,需要增加重定位项目,对每个函数调用都要重新定位地址;参数重定义,则需要修改每一个有关对应的调用指令就可以了。
( 7 )重定位表一瞥
struct IMAGE_BASE_RELOCATION BaseReloc[0] 1000h 40
struct IMAGE_BASE_RELOCATION BaseReloc[1] 2000h 78
struct IMAGE_BASE_RELOCATION BaseReloc[2] 3000h 14
struct IMAGE_BASE_RELOCATION BaseReloc[3] 4000h 4
struct IMAGE_BASE_RELOCATION BaseReloc[4] 6000h 4
struct IMAGE_BASE_RELOCATION BaseReloc[5] 7000h 14
这样理解:
从代码段虚地址1000h开始,有40个函数需要重定位(包括空白),
从代码段虚地址2000h开始,有78个函数需要重定位(包括空白),
从代码段虚地址3000h开始,有14个函数需要重定位(包括空白),
从代码段虚地址4000h开始,有4个函数需要重定位(包括空白),
从代码段虚地址6000h开始,有4个函数需要重定位(包括空白),
从代码段虚地址7000h开始,有14个函数需要重定位(包括空白),
具体是哪些函数地址需要重定位,把每个重定位段打开,例如重定位段
struct IMAGE_BASE_RELOCATION BaseReloc[0] 有40个重定位条目:
WORD Block[0] 372Ch
WORD Block[1] 3730h
WORD Block[2] 3734h
WORD Block[3] 3738h
WORD Block[4] 373Ch
WORD Block[5] 3740h
… …
这个数据,就是上面讲过的,需要要公式进行计算。
(8) 明白了地址重定位后,就能够明白以下问题了。
在EXE文件中的机器码中,机器码B8 01 00 00 00
的含义是MOV EAX,1。但我们在运行EXE时,并不能达到我们的目的,数据发生变化了,就是因为自动进行参数(变量)重定位了。
1.在010 Edito.exe中, 选择DATA段,找到空白空间92BB0H,
增加文字:
记住这4个字符串的地址是:92BB0 H, 92BC0 H, 92BD0 H, 92BE0 H
2.在010 Edito.exe中, 选择 TEXT段,找到空白空间8A110 H,
编辑代码:
这段代码实现对话框的弹出, 说明见下。至此,增加的一部分代码初步完成。
机器语言:6A 00 B8 D0 39 09 01 50 B8 B0 39 09 01 50 6A 00
FF 15 04 14 00 01 C3
对应的汇编语言是:
6A 00 PUSH 0 ;窗口风格:只有一个按钮
B8 D0390901 MOV EAX,OFFSET 010939D0 ; 窗口标题地址,说明见后
50 PUSH EAX
B8 B0390901 MOV EAX,OFFSET 010939B0 ; 窗口信息地址,说明见后
50 PUSH EAX
6A 00 PUSH 0 ;窗口的父窗口
FF15 04140001 CALL DWORD PTR DS:[<&USER32.MessageBoxW> ;
C3 RETN
3.在ollydbg.exe中, USER32.MessageBoxW 函数重定位.找到区间代码,
4.在010 Edito.exe中, 根据前面的区间代码85 FF 74 02 8B C7 56 51 50 FF 35,进行搜索找到对应位置(也可以计算地址查询到):
粘贴代码这一部分代码(MessageBoxW函数调用):FF 15 04 14 00 01
因为,在这个程序中,MessageBoxW函数调用API的地址是固定不变的(其它程序不一定在这个位置)
5. 在010 Edito.exe的TEXT 段中, 确认8A120 H地址是FF 15 04 14 00 01。函数重定向剩下最后一步。函数调用地址04 14 00 01的位置是8A122 H 。
在010 Edito.exe上图中, 打开重定向项目
struct IMAGE_BASE_RELOCATION BaseReloc[126]
因为.data 0x8A200 > 8A122 H,所以需要在这里增加定向项目。在ACDF0 h位置增加10H个字节空间:
下图红色一行就是新增加的一行
并进行编辑(ACDF0h):00 A0 08 00 10 00 00 00 22 3B 00 00 00 00。
其中00 A0 08 00就是0008A000 H,这个值接近我们需要的地址值 8A122 H, 所以输入它(地址对齐要求后2位为00)。经过换算就是text FOA = 0x89600(010 Edito工具自动计算,自己也可以手工计算), 见下图。
10 00 00 00就是00000010,表示10H个字节。
22 3B 00 00就是00003B22 H 。
计算公式如下:89600 H + 3B22 H – 3000 H = 8A122 H, 就是前面需要重新定位的DLL函数地址。
至此,DLL函数重定向完成(为何要减掉3000 H?看看重定义表的第一项就明白了)。
自己思考一下,何时进行重地位?当然是EXE刚加载到内存时,程序运行前进行的。第2个问题,因为原重定向表中没有地址接近的表项,所以只能增加这个重定向项,如果有接近地址的条目,则不需要再增加,在其中插入新项就可以了。第3个问题, 必须找到地址接近的重定向项位置插入,不能前也不能后,这是解析程序的要求。
保存文件。
6.计算参数的相对地址。在010 Edito.exe中,数据段DATA的存储地址是8A200h :
数据段DATA的装入地址是8B000 h, 整个程序的装入地址是1000000h,
即1000000 h + 8B000 H – 8A200h = 10OOE00 H.
数据的存储地址是92BBOH, 92BDOH (4个文字串,我们用这2个):
计算公式如下:10OOE00 H + 92BBOH = 10939B0 H,即B0 39 09 01
10OOE00 H + 92BDOH = 10939D0 H,即D0 39 09 01
在下图中,观察位置8A113 H 和8A119 H处的数据,确认增加的程序代码的数据地址是B0 39 09 01和D0 39 09 01。
至此,完成参数相对地址的计算。
考虑一下,参数相对地址必须加1000000 H, 而重定向表不需要加这个虚地址。
机器语言:6A 00 B8 D0 39 09 01 50 B8 B0 39 09 01 50 6A 00
FF 15 04 14 00 01 C3
对应的汇编语言是:
6A 00 PUSH 0
B8 D0390901 MOV EAX,OFFSET 010939D0
50 PUSH EAX
B8 B0390901 MOV EAX,OFFSET 010939B0
50 PUSH EAX
6A 00 PUSH 0 ; hOwner = NULL
FF15 04140001 CALL DWORD PTR DS:[<&USER32.MessageBoxW> ;
C3 RETN
7.在ollydbg.exe中, 找到程序的入口函数地址,准备调用执行我们的代码:
8.在010 Edito.exe中, 参照上图,找到程序的入口函数位置(可以计算地址最快),进行编辑:
在这一段代码(33845 H):E8 BF 05 00 00 E9 4D FD FF FF中
插入E8 C1 68 05 00,并更改即:E8 BF 05 00 00 E8 C1 68 05 00 E9 48 FD FF FF,调用执行我们的代码。注意,后一条指令的地址也受影响。
我们的程序地址C1 68 05 00对应的是 000568C1 H(运行时的地址,不是EXE中的地址,需要计算公式,道理同上省略)
这段机器指令是:
E8 BF 05 00 00 E8 C1 68 05 00 E9 48 FD FF FF
对应的汇编命令是:
E8 BF050000 CALL 01034809
E8 C1680500 CALL 0108AB10 ;调用我们的函数,并返回
E9 48FDFFFF JMP 01033F9C ;继续执行原程序
再次看一下我们的程序的位置( 8A110 H ),也就是第2图:
9.在010 Edito.exe中, 保存程序并运行,先弹出对话框后启动游戏程序:
这个界面是破解后的,改变了窗口标题,玩家名称,菜单名称,并且解除了运行目录的限制,放在任何位置都可以运行(微软的游戏程序,移动位置后就不能正常运行了, 因为原位置找不到程序了,有保护功能),并且可以改变得分(此处不贴图了,在另一篇博文里有)
这是写机器语言时,先写好汇编语言,再照搬过去。
————————————————
原文链接:https://blog.csdn.net/weixin_40554560/article/details/102775525