c++编译后会给函数签名加上很多特有的修饰,比如bool ReqGetGuildUserList(long)将会被编译成:
1 | ?ReqGetGuildUserList@@YA_NJ@Z |
用Dependency Walker这个工具可以看的很清楚的。
Dependency Walker工具一般是用来查看dll或者exe的依赖项的,这样就可以在软件发布的时候避免漏掉某些dll,当然对于动态加载的dll是没有办法的。但其中的Undecorate C++ Functions功能也甚是好用。
功能强大的Undecorate C++ Functions
Undecorate后的C++签名,这样就看的很清楚了
如果要在代码中做这样的转换也是可以的。Windows提供了一个UnDecorateSymbolName函数,用来Undecorates the specified decorated C++ symbol name。
第一个参数为输出地址,第二个参数为未修饰的名字,第三个参数为长度,第四个参数为0表示完全修饰。
作为例子,一个未修饰的函数名:
1 | private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *) |
修饰规则如下:
c++函数名的修饰更为复杂,提供的信息也更为丰富。
无论 __cdecl,__fastcall还是__stdcall调用方式,函数修饰都是以一个“?”开始,后面紧跟函数的名字。再后面是参数表的开始标识和依照参数类型代号拼出的参数表。
v2 = ?My_Aut0_PWN
对于C++的类成员函数(其调用方式是thiscall),函数的名字修饰与非成员的C++函数稍有不同,首先就是在函数名字和参数表之间插入以“@”字 符引导的类名。
v2 = ?My_Aut0_PWN@R0Pxx
其次是参数表的开始标识不同,公有(public)成员函数的标识是“@@QAE”,保护(protected)成员函数的标识是 “@@IAE”,私有(private)成员函数的标识是“@@AAE”,假设函数声明使用了constkeyword,则对应的标识应分别为“@@QBE”,“@@IBE”和“@@ABE”。
因为函数为private,私有成员
所以v2 =?My_Aut0_PWN@R0Pxx@@AAE
后面就是添加参数了,先加入函数返回值参数,函数的返回值类型为char *
参数表的拼写代号如下:
X–void
D–char
E–unsigned char
F–short
H–int
I–unsigned int
J–long
K–unsigned long(DWORD)
M–float
N–double
_N–bool
U–struct
…
指针的方式有些特别。用PA表示指针,用PB表示const类型的指针。
char *
也就是PAD
所以v2 = ?My_Aut0_PWN@R0Pxx@@AAEPAD
然后是参数的类型unsigned char *
,也就是PAE
所以v2 = ?My_Aut0_PWN@R0Pxx@@AAEPADPAE
参数表后以“@Z”标识整个名字的结束。假设该函数无参数,则以“Z”标识结束。
所以最终修饰为了:
1 | ?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z |