undname.exe:无效的未修饰名称

逆向工程 C++ 微信 改名
2021-07-03 20:35:14

我今天发现了 undname.exe 并在几个函数上尝试了它。我得到了一些不正确的结果,我想知道为什么。我认为可以做到这一点的主要原因有两个:

  • mangling 可以在 msvc 版本之间更改,我应该找到适合我的目标的 undname.exe 版本
  • 我用来提取函数名称的工具给出了不准确的结果

下面是一个错误结果的例子:

Undecoration of :- "?GetClassNameW@User@@QAE?AVFName@@H@Z"
is :- "public: class FName __thiscall User::GetClassNameW(int)"

在尝试了这个签名并收到堆栈错误后,我查看了 的反汇编代码GetClassNameW并意识到函数签名实际上是void(__thiscall* user_getClassNameW)(User*, FName*, int);

我不知道用于编译示例的 msvc 的确切版本,似乎下载 undname.exe 的唯一方法是安装 Visual Studio,因此我无法轻松测试。

知道问题可能来自哪里吗?

2个回答

正如@blabb 所说的 undname 是正确的,所以它是你的另一个“不正确”的工具。但是,值得更详细地研究这一点,因为它可能并不像您想象的那样不正确。

要理解这一点,您必须深入研究 ABI 并思考 C++ 函数调用在实践中是如何工作的。

首先,C++ 成员函数在某种意义上就像一个带有“隐藏”this指针作为第一个参数传递的 C 函数(这就是__thiscall幕后所说的。)

// this function
void class::member();
// is really
void __thiscall class::member();

// and works like
void __stdcall class_member( Class* this );

其次,返回一个('复杂')结构/类的函数的调用者负责为该结构/类分配内存,并将一个指向该内存的指针传递给函数。然后该函数可以在那里写入相关的详细信息。因此 -

// this function
complex_struct_return_type function();  

// works like
void function( complex_struct_return_type * );

将这些放在一起(并忽略可访问性说明符)-

// this function
FName __thiscall User::GetClassNameW( int param );

// works like
void __stdcall User_GetClassNameW( User* this, FName* pointer_to_return_value, int param );

您会看到这与您的其他工具的输出非常相似。我只是观察-

  • 它仍然将函数标记为__thiscall这不太合理,但可能是为了表明第一个参数在 32 位代码中有特殊处理。
  • 它正在改变首字母的大小写。这又是完全不正确的。

这些参数的传递方式(通过 msvc)取决于它是针对 32 位还是 64 位编译的。

  • 对于 32 位代码,this经过特殊处理并ecx与堆栈中的其余参数一起传入
  • 对于 64 位代码,this被视为与其他参数一样,因此,作为在寄存器中传递的最多 4 个参数中的第一个将在rcx

有很多外部实用程序可以对修饰的名称进行 demangle
尝试寻找vc++filt /
或一些像这样的在线 demangler

或者您可以使用 dbghelp api UndecorateSymbolName() 在 python 中使用 ctype / pywin32 编写一个

undname 也没有错,你的第二个猜测一定是正确的

我刚刚设计了一个类似的函数原型,并查看了它的 demangled 名称,
它与您的 demangle 名称完全不同,这里是一个 src 代码和输出

#include <windows.h>
#include <dbghelp.h>
#include <stdio.h>
void uselessname(HWND hwnd,LPWSTR lpcname,int mcnt)
{
    printf("%p %ws %d\n",hwnd,lpcname,mcnt);
    printf("%s\n%s\n%s\n",__FUNCTION__,__FUNCDNAME__,__FUNCSIG__);   

}
int main (void) 
{
    HWND cwnd =NULL;
    wchar_t cname[50] = {L"MANGLE AND DEMANGLE"};
    int cnt = 50;
    uselessname(cwnd,cname,cnt);
    char ret[0x100] = {0};
    UnDecorateSymbolName("?GetClassNameW@User@@QAE?AVFName@@H@Z",ret,0x100,0);
    printf("%s\n",ret);
    return 0;
}

输出

gcw.exe
0000000000000000 MANGLE AND DEMANGLE 50
uselessname
?uselessname@@YAXPEAUHWND__@@PEA_WH@Z   <<<<<<<<<<<<<<<<<<<<<<<<<< must be like this
void __cdecl uselessname(struct HWND__ *,wchar_t *,int)
public: class FName __thiscall User::GetClassNameW(int) <<<<< result of yours 
which is ?GetClassNameW@User@@QAE?AVFName@@H@Z