函数的名字修饰(Decorated Name)就是编译器在编译期间创建的一个字符串,用来指明函数的定义或原型。
目的是方便编译过程中,链接器等中间过程识别不同的函数,尤其是在引入重载后,识别函数不能只看函数名,要结合参数、返回值类型来识别。
C和C++程序的函数在内部使用不同的名字修饰方式,下面将分别介绍。
C函数名修饰
C不存在函数重载,主要需要在函数修饰中体现出函数的调用约定:
- __stdcall:函数名前加上一个下划线前缀,函数名后面加上一个“@”符号和其参数的字节数,例如_functionname@number。
- __cdecl:仅在输出函数名前加上一个下划线前缀,例如_functionname。
- __fastcall:在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,例如@functionname@number
C++函数名修饰
考虑到函数重载,函数名修饰需要包含调用约定,返回值类型,参数个数及类型。
总体格式为:
?+[构造/析构]+函数名+@@+调用约定+返回值类型+各个参数类型+结束标志
构造/析构
- 可选项,只有构造函数和析构函数有。
- 0:构造器
- 1:析构器
函数名
- 函数名包括类名和命名空间名,格式为:
- 函数名@类名@命名空间
调用约定
- __stdcall:@@YG
- __cdecl:@@YA
- __fastcall:@@YI
如果函数是类的成员函数,调用约定为__thiscall,根据保护方式的不同,又分为:
- public __thiscall:@@QAE
- protect __thiscall:@@IAE
- private __thiscall:@@AAE
- public __thiscall const:@@QBE
- protect __thiscall const:@@IBE
- private __thiscall const:@@ABE
返回值、参数的类型标识
- B:const
- D:char
- E:unsigned char
- F:short
- G:unsigned short
- H:int
- I:unsigned int
- J:long
- K:unsigned long
- M:float
- N:double
- _N:bool
- PA:指针(*,后面的代号表明指针类型,如果相同类型的指针连续出现,以0代替,一个0代表一次重复)
- PB:const指针
- AA:引用(&)
- AB:const引用
- U:类或结构体,通常后跟结构体的类型名,用“@@”表示结构类型名的结束。
- V:类,通常后跟结构体的类型名,用“@@”表示结构类型名的结束
- W4:enum
- X:void
- Z: 结尾标记
- 0:相同类型的指针连续出现,以“0”代替,一个“0”代表一次重复。
- @: 空,无得意思,构造或析构使用
- AAV1:参数类型是类实例的引用,通常后跟结构体的类型名,用“@@”表示结构类型名的结束。
- ABV1:参数类型是const类实例的引用,通常后跟结构体的类型名,用“@@”表示结构类型名的结束。
- ?AV:函数返回值为某个类,通常后跟结构体的类型名,用“@@”表示结构类型名的结束
- ?BV:函数返回值为某个类的const,通常后跟结构体的类型名,用“@@”表示结构类型名的结束
- PAV:返回值为某个类的指针,通常后跟结构体的类型名,用“@@”表示结构类型名的结束
- AAV:返回值为某个类的引用,通常后跟结构体的类型名,用“@@”表示结构类型名的结束
- PBV:返回值为某个类带有const性质的指针,通常后跟结构体的类型名,用“@@”表示结构类型名的结束
- ABV:返回值为某个类带有const性质的引用,通常后跟结构体的类型名,用“@@”表示结构类型名的结束
- V1@:函数参数为某个类的时候,并且该参数所使用的类曾经出现过
结束标志
- 参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“Z”标识结束。
———————————————————————————————————————————
欢迎关注我的微博:大雄_RE。专注软件逆向,分享最新的好文章、好工具,追踪行业大佬的研究成果。