用过CFF Explorer之后,发现它可以给EXE添加Seciton,甚至还可以直接导入一个文件作为EXE中一个Section,功能好赞。配合OllyDBG来对现有软件的EXE做一些小小的hack感觉效果很好。
最早的时候我是直接用OllyDBG打开EXE,然后找到一片都是0的地方来汇编代码进去。但是这样受到的限制很多,最直接的就比如有的时候找不到一堆0的地方,找到也不确定能不能写:有可能这些部分其他地方要用,又或者汇编了代码进去要保存的时候OllyDBG说存不了。现在可以直接自己添加一个Section,不会出现找不到空间的情况了。
既然可以导入文件,那比起直接在OllyDBG里面敲汇编,用Nasm来写汇编代码要方便得很多。在测试导入Nasm写的汇编以后,我就在捉摸着更加方便的事情:用C语言来写。
我选用的是OpenWatcom C编译器,没什么太多理由,正好抓到它而已。它反正也可以生成Raw二进制格式的文件。
研究了一下它的链接器,最终的结果是用这样的参数:
OPTION OFFSET=xxxxxx FORMAT RAW BIN
或者
OUTPUT RAW OFFSET=xxxxxx
一起用就会出一些奇怪的结果。说明文档非常长,不知道是不是哪里漏掉了什么没看到的部分……
一起用的时候有的时候就出现最前面16个字节全部是0,然后后面的代码全部错位,大汗……
比如gimp 2.8的补丁,实际上就是调用一下msvcrt.dll里面的_putenv,给一个LANG=en就完事了。代码如下:
void __stdcall gimppatch(int param); void callgp() { gimppatch(1); } extern "C" void* (__stdcall **fGetModuleHandleA)(const char*); extern "C" void* (__stdcall **fGetProcAddress)(void*, const char*); void __stdcall gimppatch(int param) { int* p = ¶m; p--; *p = 0x4014b0; void* msvcrt = fGetModuleHandleA("msvcrt.dll"); int (__cdecl *putenv)(const char*) = (int (__cdecl*)(const char*)) fGetProcAddress(msvcrt, "_putenv"); putenv("LANG=en"); }
函数指针的解释:因为函数地址在导入表中,于是导入表对应位置里保存的事实上就是一个函数指针,然后导入表对应位置的地址( fGetProcAddress 的值)就是指向函数指针的指针。
然后要链接嘛,链接的时候那些符号由另一个文件提供:
section .text global _fGetModuleHandleA global _fGetProcAddress section .code _fGetModuleHandleA: dd 0x960b54 _fGetProcAddress: dd 0x960b58
于是编译链接:
wpp386 -s gimpPatch.cpp
其中 -s 是防止它检查堆栈溢出啥的,因为会导致一个CHK链接不上
然后另一边就直接
nasm -f win32 gimpImp.asm
链接即可:
wlink f gimpPatch.obj f gimpImp.obj form raw bin op off=0x98a000 name gimpPatch.bin
其中98a000是看了gimp-2.8.exe的section,把最后一个section的起始地址加上大小得到要增加的新section的起始地址:0x589000 + 0x200 = 0x589200,然后新section要对齐到4k边界,就变成0x58a000了。然后加上加载的基址0x400000得到0x98a000。(话说我发现,这参数好像还有顺序问题的样子……)
用CFF Explorer导入以后,找到之前C语言callgp函数,就留下push 1和call,前面的全部nop掉。之所以要弄一个callgp函数,是为了gimppatch执行完毕之后能够正确跳回exe入口,于是把gimppatch的返回地址给改成gimp的原入口处。之后改一下EXE的入口,到callgp函数所在位置,修改就结束了。
追记:
1、wlink的参数似乎是有顺序的,注意那个warning,可以知道offset参数到底有没有正常
2、文章中提到的方法,调用参数的时候都是用的函数指针,很蛋疼。如果想直接#incude <windows.h>的话,那个asm文件要稍微改一改。比如这个
section .text global __imp__WriteConsoleW@20 global __imp__HeapFree@12 global __imp__MultiByteToWideChar@24 global __imp__HeapAlloc@12 global __imp__GetProcessHeap@0 global __imp__VirtualProtect@16 global __imp__GetProcAddress@8 global __imp__GetModuleHandleW@4 global __imp__RtlMoveMemory@12 section .data __imp__WriteConsoleW@20 equ 0x60a143 __imp__HeapFree@12 equ 0x60a14b __imp__MultiByteToWideChar@24 equ 0x60a163 __imp__HeapAlloc@12 equ 0x60a147 __imp__GetProcessHeap@0 equ 0x60a14f __imp__VirtualProtect@16 equ 0x60a157 __imp__GetProcAddress@8 equ 0x60a153 __imp__GetModuleHandleW@4 equ 0x60b0d4 __imp__RtlMoveMemory@12 equ 0x60a15b