《黑客反汇编揭密》第5章例子的编译

在《黑客反汇编揭密》第5章的“第四步:熟练使用调试器”一节有一个例子CrakMe0x30的源码示例,由于展示程序的重定位。上面的源码,这里就不重新列出了,这里主要就其编译时做一些说明。
为了方便自己,我重新写一个类似的例子:


#include
#include

#pragma comment(lib,"kernel32.lib")
#pragma comment(lib,"user32.lib")

__declspec(dllexport) void MyMsg(char *szText){
  MessageBox(NULL,"Test MsgBox",szText,0);
}

int main(){
  typedef void (*MYMSG)(char *);
  HMODULE hMod;
  hMod=LoadLibrary("test.exe");

  if(!hMod){
    MessageBox(NULL,TEXT("载入失败!"),TEXT("提示信息"),0);
    return 0;
  }
  
  MYMSG addr=(MYMSG)GetProcAddress(hMod,"MyMsg");
  if(!addr){
    MessageBox(NULL,TEXT("获取函数地址失败!"),TEXT("提示信息"),0);
    return 0;
  }
  printf("%08X\n",(DWORD)addr);
  addr("test load");
  ::FreeLibrary(hMod);
  
  return 0;
}

如果现在直接在命令行下编译,则永远都会出错,出错的原因都是获取函数地址出错。
为什么??主要是编译器对函数名的修饰。各种编译器修饰的方法不尽相同。这里,我们打开生成的Lib文件看一下就知道了:


00000000h: 21 3C 61 72 63 68 3E 0A 2F 20 20 20 20 20 20 20 ; !<arch>./      
00000010h: 20 20 20 20 20 20 20 20 31 32 33 39 33 36 39 34 ;         12393694
00000020h: 32 38 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; 28              
00000030h: 30 20 20 20 20 20 20 20 31 33 36 20 20 20 20 20 ; 0       136    
00000040h: 20 20 60 0A 00 00 00 05 00 00 01 9E 00 00 03 BC ;   `........?..?
00000050h: 00 00 04 F0 00 00 06 3C 00 00 06 3C 5F 5F 49 4D ; ...?..<...<__IM
00000060h: 50 4F 52 54 5F 44 45 53 43 52 49 50 54 4F 52 5F ; PORT_DESCRIPTOR_
00000070h: 74 65 73 74 00 5F 5F 4E 55 4C 4C 5F 49 4D 50 4F ; test.__NULL_IMPO
00000080h: 52 54 5F 44 45 53 43 52 49 50 54 4F 52 00 7F 74 ; RT_DESCRIPTOR.t
00000090h: 65 73 74 5F 4E 55 4C 4C 5F 54 48 55 4E 4B 5F 44 ; est_NULL_THUNK_D
000000a0h: 41 54 41 00 3F 4D 79 4D 73 67 40 40 59 41 58 50 ; ATA.?MyMsg@@YAXP
000000b0h: 41 44 40 5A 00 5F 5F 69 6D 70 5F 3F 4D 79 4D 73 ; AD@Z.__imp_?MyMs
000000c0h: 67 40 40 59 41 58 50 41 44 40 5A 00 2F 20 20 20 ; g@@YAXPAD@Z./  

这里修饰后的函数名就是:[color=#FF0000]MyMsg@@YAXPAD@Z[/color]
如果我们在程序里将GetProcAddress函数的调用修改为如下:
MYMSG addr=(MYMSG)GetProcAddress(hMod,”MyMsg@@YAXPAD@Z”);
则会调用成功并得到预期的结果,但这样不方便。

为了能如常编译上面的源码,我们需要新建一个Def文件:


/*************************
FileName:  test.def
*************************/
EXPORTS
  MyMsg

这样一来,我们在编译时指定一下DEF文件,如:


E:\Programming>cl test.cpp /EHsc test.def
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
/def:test.def
test.obj
   Creating library test.lib and object test.exp

这样编译成功后,就能得到预期的结果了,呵呵!

发表评论