patch代码要寻找ff15组合和ff25组合的指如下两种情况:
----------
00301218 FF 15 AC A2 32 00 call dword ptr [__imp__MessageBoxA@16 (0032a2ac)]
--------------------
0030120A E8 1D 00 00 00 call Sleep (0030122c)
0030122C FF 25 4C A1 32 00 jmp dword ptr [__imp__Sleep@4 (0032a14c)]
------------------------
为了保证是真实的api调用指令
算法一
1 我们可以只对code段进行搜索,在段头中characteristics有code属性20h即可。
2 a 因为IAT在文件里一定是填写了thunk_data的rVA,所以,可以假定后面的地址就是
IAT的地址,将该地址指向内存的值取出,作为thunk_data入口,然后偏移两字节,跳过序号
后4字节就是函数名的RVA,再用RVA换算成文件偏移,如果该函数名就是我们希望patch的函数调用,那么ok。但要注意的是无效的RVA的无效性,应该排除,见下段描述。
b 而RVA换算成文件偏移如下,变量节头(有节的起始RVA和节内存大小),看此RVA在哪个节内,此RVA-段首RVA为段内偏移d,然后节头有段首文件偏移字段+d则为文件偏移。在此RVA
换算文件偏移过程中,一个节都不属于的就是无效RVA
c 另外,我们需要将IAT项的地址换算成文件偏移,因为call或jmp指令后是用4字节的地址
而不是文件偏移。只有换成文件偏移,我们才能获取到IAT项中的内容。我们将这个地址 -
imagebase就是文件的内存偏移量。即RVA,然后用上面b的方法转换成文件偏移即可
算法二
1 找到关注的api的导入表项的firstthunk的RVA,加上imagebase为va,虚地址ft。且找到关注API的那个iat项的地址iat_func1。这里要找到相关项,依然要从iat的内容RAV切换到文件偏移,否则无法找到函数名。这里可以参考算法1的b,c相关部分。
2 我们可以只对code段进行搜索,在段头中characteristics有code属性20h即可。
3 拿到call或jmp后的地址a后,if a = iat_func1,则就是我们关注的调用。当然,真正调用者肯定满足第3条,反过来满足者并非一定可用。所以依然是概率性。
我们采用算法2计算。
用endattach去修改testexe的程序。对比检查是否被patch的地方正确。
testexe在调用两个api之前都有全局变量赋值,且赋值的都是特殊数值,便于对比查找
对比时,用ultraedit打开修改前后的testexe的程序,然后输入那些特殊数,比较后续指令
是否patch正确。
特别的,我们故意在数据区加入了指令前缀,因此要验证这些没有被patch
另外,在代码区,也加入了貌似符合的指令ff15, ff25但他们并非真正的api调用指令,
我们让它的RVA:1为无效RVA(超出section范围),2 指向有效区域,但内容不是API名字
3,内容是API的名字,但该内存的地址并非输入导入表项对应地址(如算法2第3步)
其中1,3没在testexe中测试
patch 成一个jmp指令,跳到指定位置