提交第一个版本时因为没有仔细看评分条件, 所以最初是考虑感染型修改, 尽可能少的修改原始文件, 因此除了添加一个EAT之外所有的代码和数据都存放在text段内未使用的空间里而且代码还包括定位KERNEL32的基地址,寻找GetProcAddress,加载SHELL32.DLL及ShellExecuteA并运行之, 但这样一来的结果是整个函数变得非常臃肿... :(
因此又重新做了一次
此时为了尽可能精简OpenUrlA函数, 考虑了以下几个问题
最后的函数调用肯定是不能像第一个版本那样再自己查找了, 所以对IAT的修改在所难免. 我们需要加入一个函数, 因此第一步先将Import Directory向后移动8个字节并重新构造, 在Import Directory Terminator之前插入一条新的Entry用以加载WinExec, 这里我重复利用了第一条Entry中的KERNEL32.DLL字符串
IAT修改完成后下一个目标是EAT, 因为这个DLL本身没有EAT, 所以需要构造一个新的EAT, 基本上就接着IAT写下去, 但我在IAT和EAT之间还插入了WinExec需要执行的命令字符串"explorer.exe
http://bbs.pediy.com", 暂时先跳过这点后面会讨论到, EAT构造完成后将导出函数OpenUrlA指向text段末尾没有用到的地址4010EB(这里本来可以指向4010CA, 但刚开始因为一些其他考虑在4010CA写了WinExe需要执行的命令字符串, 而且后来也忘记删除了)
现在已经可以执行OpenUrlA函数了, 但为了让OpenUrlA函数尽可能简短, 显然用ShellExecuteA已经不合适了, 因为它的需要的参数太多, 因此换成WinExec, 调用"explorer.exe
http://bbs.pediy.com"开启连接, 这里也算是偷了个懒, explorer.exe的路径无须指定, 系统会自动寻找, 并且explorer.exe会自动调用浏缆器开启网页, 这里最简单的做法显然是
6A 01 push 01
68 D7 20 40 00 push offset "explorer.exe
http://bbs.pediy.com"
FF 15 14 20 40 00 call WinExec
C3 retn
但上面这种做法函数长度是2+5+6+1=14个字节
怎样才能更精简呢? 显然push 01和retn是不可能精简的, 但注意到中间的两条指令都用了绝对地址非常浪费长度, 因此肯定是要拿他们动手了, 改成如下代码
6A 01 push 01
B8 D7 20 40 00 mov eax, offset "explorer.exe
http://bbs.pediy.com"
50 push eax
2C C3 sub al, 0C3h
FF 10 call dword ptr [eax]
C3 retn
这里的考虑是尽量避免使用绝对地址, mov指令和后面一条push eax很容易理解, 之后再把al减了0C3h, 为什么是AL而不是EAX, 因为减EAX的话至少需要3个字节. 这就是为什么我把字符串"explorer.exe
http://bbs.pediy.com"放在IAT之后的原因, 这样一来EAX的值将会变成402014h, 随后再用两个字节call dword ptr [eax]调用WinExe, 最后C3返回, 现在长度是2+5+1+2+2+1=13个字节
大功告成? 呵呵, 还差一步, 因为ImageBase是400000h, 这个地址多半已经被其他模块占用了, 因此还需要修改reloc表, 再最后添加一条记录30EE用于修改mov这条指令所用到的绝对地址
最后, XP上测试正常, 因为手边没有2000也就不测试了