本來應(yīng)該用高級評論將重點高亮的,但不知道cppblog出了什么問題用不了。只能眼睛尖點了。。。
1. test files
module.c 導(dǎo)出1個變量與3個函數(shù)
__declspec(dllexport) int error_code;
__declspec(dllexport) int get(void) { return error_code; }
__declspec(dllexport) void set(int x) { error_code = x; }
int main(void) { return 0; }
main.c 輸出變量地址、函數(shù)地址以及函數(shù)包含的指令
#include <stdio.h>
__declspec(dllimport) int error_code;
__declspec(dllimport) int get(void);
__declspec(dllimport) void set(int x);
int main(void)
{
int i;
unsigned char const* p;
printf("%p\n", (void*)&error_code);
p = (unsigned char*)get;
printf("%p:", p);
for (i=0; i<12; ++i) printf(" %02X", p[i]);
printf("\n");
p = (unsigned char*)set;
printf("%p:", p);
for (i=0; i<12; ++i) printf(" %02X", p[i]);
printf("\n");
return 0;
}
2. dll
編譯
cl /LD /O1 module.c /link /noentry
查看首選基地址
dumpbin /all module.dll | find /i "image base"
10000000 image base (10000000 to 10004FFF)
查看反匯編與重定項
dumpbin /disasm /relocations module.dll
File Type: DLL
10001000: A1 00 30 00 10 mov eax,dword ptr ds:[10003000h]
10001005: C3 ret
10001006: 8B 44 24 04 mov eax,dword ptr [esp+4]
1000100A: A3 00 30 00 10 mov dword ptr ds:[10003000h],eax
1000100F: C3 ret
BASE RELOCATIONS #4
1000 RVA, C SizeOfBlock
1 HIGHLOW 10003000
B HIGHLOW 10003000
10001000 處(get的第1條)指令的操作數(shù)(地址在10001001)是 10003000
1000100A 處(set的第2條)指令的操作數(shù)(地址在1000100B)也是 10003000
注意"File Type: DLL",這是根據(jù)PE的域來的。
編譯并運(yùn)行得到的輸出是
cl main.c module.lib && main.exe
10003000
10001000: A1 00 30 00 10 C3 8B 44 24 04 A3 00
10001006: 8B 44 24 04 A3 00 30 00 10 C3 00 00
error_code的地址和指令中使用的地址是相同的。
3. dll relocation
上面 module.dll 恰好加載在首選基地址,所以沒有發(fā)生重定項。
要演示重定項發(fā)生的情況, 可以將 module.dll 復(fù)制一份, 然后用 LoadLibrary 加載。
或者直接首選基地址為一個會沖突的, exe的默認(rèn)基地址0x400000。
cl /LD /O1 module.c /link /noentry /base:0x400000
dumpbin /all module.dll | find /i "image base"
400000 image base (00400000 to 00404FFF)
dumpbin /disasm /relocations module.dll
00401000: A1 00 30 40 00 mov eax,dword ptr ds:[00403000h]
00401005: C3 ret
00401006: 8B 44 24 04 mov eax,dword ptr [esp+4]
0040100A: A3 00 30 40 00 mov dword ptr ds:[00403000h],eax
0040100F: C3 ret
BASE RELOCATIONS #4
1000 RVA, C SizeOfBlock
1 HIGHLOW 00403000
B HIGHLOW 00403000
cl main.c module.lib && main.exe
00393000
00391000: A1 00 30 39 00 C3 8B 44 24 04 A3 00
00391006: 8B 44 24 04 A3 00 30 39 00 C3 00 00
對比 dumpbin 得到的反匯編與 main.exe 的輸出,可以發(fā)現(xiàn)指令中的操作數(shù)有相應(yīng)的修改,以正確的使用00393000上的變量error_code。
4. dll fixed
如果鏈接時選擇基地址固定
cl /LD /O1 module.c /link /noentry /base:0x400000 /fixed
產(chǎn)生的dll里就沒有重定項信息
dumpbin /relocations module.dll
并且選擇的是一個肯定會沖突的基地址,所以加載main.exe就會失敗。
main.exe
5. exe export
默認(rèn)exe是不會包含重定項信息的
cl /O1 module.c && dumpbin /relocations module.exe
File Type: EXECUTABLE IMAGE
注意"File Type: EXECUTABLE IMAGE",這是根據(jù)PE的域來的。
并且首選基地址也是沖突的。
dumpbin /all module.exe | find /i "image base"
400000 image base (00400000 to 0040BFFF)
但是讓 main.c 鏈接到 module.exe 可以運(yùn)行成功(之前dll fixed的情況是加載 main.exe 失敗)
cl main.c module.lib & main.exe
0039B700
00391000: A1 00 B7 40 00 C3 8B 44 24 04 A3 00
00391006: 8B 44 24 04 A3 00 B7 40 00 C3 33 C0
注意指令里的操作碼,并沒有修改為error_code的地址:0039B700。
如果真的調(diào)用了get和set,也只是讀寫了其他的地址,而不是error_code。
bug已經(jīng)產(chǎn)生了。 沒崩只是運(yùn)氣, 那個地址恰好有讀寫權(quán)限。
而且實驗代碼一般都比較短,跑完馬上就退出了,這種意外的寫入產(chǎn)生的影響也不一定能發(fā)現(xiàn)。
6. exe export with relocation information
可以用 /fixed:no 附帶上重定項信息
cl /O1 module.c /link /fixed:no
dumpbin /relocations module.exe 會產(chǎn)生很多輸出,因為它還引用了libc。
而讓 main.c 鏈接到 module.exe 并運(yùn)行的同樣不會發(fā)生重定項
cl main.c module.lib & main.exe
0039B700
00391000: A1 00 B7 40 00 C3 8B 44 24 04 A3 00
00391006: 8B 44 24 04 A3 00 B7 40 00 C3 33 C0
回復(fù) 更多評論