原文:https://www.pediy.com/kssd/pediy10/73927.html
已经过了保密时间,现在公开下我的做题答案,祥见附件。答案缺点是兼容性差,直接使用了LoadLibrary,GetProcAddress.FreeLibrary等函数地址。
优点当然是修改的地方少了。
恐怕函数占用字节数我是最多的了。呵呵,重在参与。这些不重要了。抛砖引玉吧。
1. 数据目录中添加导出表结构 20b0(6B0)
在pediy.dll文件148h处添加字节:b0 20 00 00 45 00 00 00
2. 添加导出表
在pediy.dll文件6b0处添加如下字节:用作导出表
00 00 00 00 34 cf e5 48 00 00 00 00 e2 20 00 00
01 00 00 00 01 00 00 00 01 00 00 00 d8 20 00 00
dc 20 00 00 e0 20 00 00 20 11 00 00 ec 20 00 00
00 00 70 65 64 69 79 2e 64 6c 6c 00 4f 70 65 6e
55 72 6c 41 00
3. 添加导出函数
在pediy.dll文件520h处添加机器码:
53 57 56 E8 00 00 00 00 5B 81 EB 28 11 40 00
8D B3 00 11 40 00 56 BF 77 1D 80 7C FF D7 50
5F 8D B3 10 11 40 00 56 57 B8 28 AC 80 7C FF
D0 6A 01 6A 00 6A 00 8D B3 e0 10 40 00 56 8D
B3 d0 10 40 00 56 6A 00 FF D0 57 B8 66 AA 80
7C FF D0 5E 5F 5B C3
在.text中添加常量字符串。
1) 在pediy.dll文件4e0h处添加: 68 74 74 70 3A 2F 2F 26 62 73 2E 70 65 64 69 79 2E 63 6F 6D 00
2) 在pediy.dll文件4d0h处添加: 6F 70 65 6E 00
3) 在pediy.dll文件500h处添加: 73 68 65 6C 6C 33 32 2E 64 6C 6C 00
4) 在pediy.dll文件510h处添加: 53 68 65 6C 6C 45 78 65 63 75 74 65 41 00
到这里题目就完成了。
测试代码:
HMODULE hd = LoadLibrary("pediy.dll");
GetProcAddress(hd,"OpenUrlA");
_asm call eax
FreeLibrary(hd);
本来我这样做。第一次提交
加了SHELLEXECUTEA
3X字节
003F10CA . 60 pushad
003F10CB . E8 00000000 call 3.003F10D0 代码自身重定位
003F10D0 /$ 58 pop eax
003F10D1 |. 6A 00 push 0
003F10D3 |. 6A 00 push 0
003F10D5 |. 8BC8 mov ecx, eax
003F10D7 |. 83C1 1C add ecx, 1C
003F10DA |. 51 push ecx
003F10DB |. 83C1 06 add ecx, 6
003F10DE |. 51 push ecx
003F10DF |. 6A 00 push 0
003F10E1 |. 6A 01 push 1
003F10E3 |. 05 4C3F0000 add eax, 3F4C
003F10E8 |. FF10 call dword ptr [eax] SHELLEXECUTEA
003F10EA |. 61 popad
003F10EB \. C3 retn
后来
我加了2重定位 还是用SHELLEXECUTEA
19字节
003F10CA . 33C0 xor eax, eax
003F10CC . 50 push eax ; /IsShown => 0
003F10CD . 50 push eax ; |DefDir => NULL
003F10CE . 50 push eax ; |Parameters => NULL
003F10CF . 68 F2103F00 push 复件_(3).003F10F2 ; |FileName = "http://bbs.pediy.com" 重定位
003F10D4 . 50 push eax ; |Operation => NULL
003F10D5 . 50 push eax ; |hWnd => NULL
003F10D6 . FF15 AA203F00 call dword ptr [<&SHELL32.ShellExecut>; \ShellExecuteA 重定位
003F10DC . C3 retn
后来 改了WINEXEC 汗 第2次提交
14字节
003F10CA . 6A 01 push 1 ; /ShowState = SW_SHOWNORMAL
003F10CC . 68 F2103F00 push 复件_2.003F10F2 重定位 ; |CmdLine = "explorer.exe http://bbs.pediy.com"
003F10D1 . FF15 08203F00 call dword ptr [<&KERNEL32.WinExec>] 重定位 ; \WinExec
003F10D7 . C3 retn
003F10CA . 6A 01 push 1 ; /ShowState = SW_SHOWNORMAL
push eax就行,省1字节。显示状态随便为什么了,最后显示出来的是ieexplorer.exe.
将输入表向下移位0x50。。在输入表前加入winexec参数1,就能压缩到12byte;
0600h: 65 78 70 6C 6F 72 65 72 2E 65 78 65 20 68 74 74 explorer.exe htt
0610h: 70 3A 2F 2F 62 62 73 2E 70 65 64 69 79 2E 63 6F p://bbs.pediy.co
0620h: 6D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 m...............
0630h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0640h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0650h: E2 20 00 00 D6 20 00 00 F3 20 00 00 00 00 00 00 . ... ... ......
0660h: BC 20 00 00 00 00 00 00 B4 20 00 00 00 00 00 00 . ....... ......
0670h: 00 00 00 00 CA 20 00 00 60 20 00 00 A4 20 00 00 ..... ..` ... ..
0680h: 00 00 00 00 00 00 00 00 FE 20 00 00 50 20 00 00 ......... ..P ..
0690h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
06A0h: 00 00 00 00 E2 20 00 00 D6 20 00 00 F3 20 00 00 ..... ... ... ..
06B0h: 00 00 00 00 BC 20 00 00 00 00 00 00 BE 01 4D 65 ..... ........Me
06C0h: 73 73 61 67 65 42 6F 78 41 00 55 53 45 52 33 32 ssageBoxA.USER32
06D0h: 2E 64 6C 6C 00 00 99 01 48 65 61 70 41 6C 6C 6F .dll....HeapAllo
06E0h: 63 00 40 01 47 65 74 50 72 6F 63 65 73 73 48 65 c.@.GetProcessHe
06F0h: 61 70 00 00 00 57 69 6E 45 78 65 63 00 00 4B 45 ap...WinExec..KE
0700h: 52 4E 45 4C 33 32 2E 64 6C 6C 00 00 00 00 00 00 RNEL32.dll......
OpenUrlA 12 byte代码部分:
003C10CA > B8 00203C00 mov eax, 003C2000 ; ASCII "explorer.exe http://bbs.pediy.com"或cmd start命令也可
003C10CF 6A 05 push 5
003C10D1 50 push eax
003C10D2 FF50 58 call dword ptr [eax+58]
003C10D5 C3 retn
未添加节,没修改文件大小,可通用。
如果根据那测试程序的话,,可以压缩到更小。。但通用性不高,9byte也可以实现,但如果DLL进行初始化处理,就不能了。。
用lordpe添加了一个导入函数WinExec
然后用WinExec("Explorer http://bbs.pediy.com", SW_SHOW);来打开网页
然后修改两处从定位表
感觉14个字节挺标准的,呵呵
6A 05 push 5 ; /ShowState = SW_SHOW
68 47304000 push 0042201C ; |CmdLine = "Explorer http://bbs.pediy.com"
FF15 17504000 call dword ptr [<&KERNEL32.WinExec>] ; \WinExec
C3 retn
本来想手动添加导入函数,但是没有经验,参考了书上的做法(用lordpe),
结果多了一个节,失败,呵呵。但在提交时才发现不添加节加分,哎,懒得再改了。
12字节,将ShellExecuteEx的参数预先放在数据区,直接调用即可。数据区的布局用数组表示为如下:
//sizeof(SHELLEXECUTEINFO)=0x3c,15个DWORD
DWORD ShellEx[] = {
0x0000003C, //1,cbSize
0x00000000, //2
0x00000000, //3
0x00000000, //4
0x00424a30, //5, lpFile,指向"http://bbs.pediy.com",地址需要重定位;
0x00000000, //6
0x00000000, //7
0x00000000, //8
0x00000000, //9
0x00000000, //10
0x00000000, //11
0x00000000, //12
0x00000000, //13
0x00000000, //14
0x00000000 //15
};
在OpenUrlA函数填充的代码表示如下,实际可能略有不同,还需要重定位:
.text:00401000 68 58 60 40 00 push offset ExecInfo ; lpExecInfo
.text:00401005 FF 15 9C 50 40 00 call ds:ShellExecuteExA
.text:0040100B C3 retn
这种方法要添加输入表,输出表,重定位信息。但是没添加节,也没修改文件大小。
我想Aker大大说的12字节就是这样子吧,要压缩在个位数内并且通用,不知怎么弄了?
函数的大小关键在--使用哪个api
13楼的Api这样使用
0100739D > B8 56341200 mov eax, 123456
010073A2 50 push eax
010073A3 FF50 70 call dword ptr [eax+70]
010073A6 C3 retn
这样会省一个字节
10字节。
我是用错了api的
1,构造数据 004020C0 WinExec函数地址(4字节),WinExec导入表的FirstThunk指向这个双字 004020C4 0 004020C8 explorer.exe http://bbs.pediy.com/ 004020EA 2,构造指令序列(12字节) 004010D0 . 6A 01 push 1 004010D2 . B8 C8204000 mov eax, pediy.004020C8 ; ASCII "explorer.exe http://bbs.pediy.com/" 004010D7 . 50 push eax 004010D8 . FF50 F8 call dword ptr [eax-8] ; kernel32.WinExec 004010DB . C3 retn 3,添加WinExec的导入项 略 4,添加重定位项 如步骤2,004010D3处需要重定位 5,添加导出函数 导出函数为OpenUrlA 说明:未添加新节,未增大文件大小
1。ShellExecuteExA
2。WinExec
3。ShellExecuteA
原来是把参数给移出去了,实在没想到...
我开始也是搜索LoadLibraryA来着,不过通过PEB搜Kernel32基址,代码比LZ的还要长...不过这个确实稳定。
长见识了,ShellExecuteExA()这个API,只用压一次参数,比WinExec还省...
可怜我CreateProcessA写了40多字节
:
003F10CA . 60 PUSHAD
003F10CB . 6A 44 PUSH 44 ; _STARTUPINFO.cb = 44
003F10CD . B9 10000000 MOV ECX,10 ; 压入40字节的0作为缓冲区
003F10D2 > 6A 00 PUSH 0
003F10D4 .^ E2 FC LOOPD SHORT pediy.003F10D2
003F10D6 . 54 PUSH ESP ; /pProcessInfo
003F10D7 . 54 PUSH ESP ; |pStartupInfo
003F10D8 . 6A 00 PUSH 0 ; |CurrentDir = NULL
003F10DA . 6A 00 PUSH 0 ; |pEnvironment = NULL
003F10DC . 6A 00 PUSH 0 ; |CreationFlags = 0
003F10DE . 6A 00 PUSH 0 ; |InheritHandles = FALSE
003F10E0 . 6A 00 PUSH 0 ; |pThreadSecurity = NULL
003F10E2 . 6A 00 PUSH 0 ; |pProcessSecurity = NULL
003F10E4 . 68 80303F00 PUSH 003F3080 ; |CommandLine = "-e bbs.pediy.com"
003F10E9 . 68 50303F00 PUSH 003F3050 ; |ModuleFileName = "C:\Program Files\Internet Explorer\iexplore.exe"
003F10EE . FF15 5D503F00 CALL DWORD PTR DS:[<&KERNEL32.CreateProc>; \CreateProcessA
003F10F4 . 83C4 44 ADD ESP,44 ; 修正之前压入的44字节
003F10F7 . 61 POPAD
003F10F8 . C3 RETN
20多个字节才实现的,当时没想到WinExec,字节全都用在传递参数上了。