第1部分
PE 导入 thunk 的工作方式与 ELF PLT 不同。第一次调用时没有调用动态解析器,但所有导入指针都会在进程启动时提前解析(类似于LD_BIND_NOW)。指针被分组在一个类似 GOT 的导入地址表 (IAT) 中,包含有关 DLL 和导入符号的详细信息的元数据存储在由 PE 标头引用的导入目录中。
要恢复符号,您需要解析导入目录。详细信息可以在官方PE 格式规范中找到。
第2部分
编辑后,您似乎正在处理本机到托管代码 thunk。
我已经完成了以下实验以生成混合可执行文件:
m.cpp (托管代码):
using namespace System;
void hello()
{
    String^ str = "Hello World";
    Console::WriteLine(str);
}
n.cpp (本机代码):
void hello();
void main()
{
  hello();
}
编译并链接:
cl /c /clr /Zi m.cpp
cl /c /Zi n.cpp
link /debug /out:mixed.exe m.obj n.obj
拆卸本地部分(并通过 PDB 获得符号)后,我可以观察到以下内容:
.text:00007FF798E81090 main proc near     
.text:00007FF798E81090 sub     rsp, 28h
.text:00007FF798E81094 call    ?hello@@YAXXZ ; hello(void)
.text:00007FF798E81099 xor     eax, eax
.text:00007FF798E8109B add     rsp, 28h
.text:00007FF798E8109F retn
.text:00007FF798E8109F main endp
通话后:
.nep:00007FF798ECC000 ?hello@@YAXXZ proc near
.nep:00007FF798ECC000 jmp     short loc_7FF798ECC00A
.nep:00007FF798ECC002 ud2
.nep:00007FF798ECC004 jmp     cs:__m2mep@?hello@@$$FYAXXZ
.nep:00007FF798ECC00A loc_7FF798ECC00A:
.nep:00007FF798ECC00A jmp     cs:__mep@?hello@@$$FYAXXZ
.nep:00007FF798ECC00A ?hello@@YAXXZ endp
最后,遵循jmp:
.data:00007FF798EE7000 __m2mep@?hello@@$$FYAXXZ dq 6000001h
.data:00007FF798EE7008 __mep@?hello@@$$FYAXXZ dq 6000001h
值 6000001 是一个CLR 令牌。高字节字节是令牌种类,或元数据表索引,在本例中为 0x6 表示Method。在 .NET 查看器(如 ILDASM 或 dnSpy)中查找它,我们可以看到它引用了 RVA 的托管方法“hello” 000010a0。转到那个地址,我们看到:
.text:00007FF798E810A0 ?hello@@$$FYAXXZ:
.text:00007FF798E810A0 add     esi, [rax]
.text:00007FF798E810A2 add     [rax], eax
.text:00007FF798E810A4 sldt    word ptr [rax]
.text:00007FF798E810A7 add     [rdx], al
.text:00007FF798E810A9 db 2 dup(0), 11h
.text:00007FF798E810AC hello:
.text:00007FF798E810AC adc     al, 0Ah
.text:00007FF798E810AE jb      short loc_7FF798E810B1
.text:00007FF798E810B0 db 0
.text:00007FF798E810B1 loc_7FF798E810B1:
.text:00007FF798E810B1 add     [rax+0Ah], dh
.text:00007FF798E810B4 dd 22806h
.text:00007FF798E810B8 db 0, 0Ah, 2Ah, 0CCh
它作为 x64 代码没有任何意义,因此这显然是 CLI 字节码,应该使用 .net 反编译器进行检查。奇怪的是,我尝试的那些似乎都没有显示该功能,但我设法从 ILDASM 获得了 IL 反汇编:
.method /*06000001*/ assembly static void modopt([mscorlib/*23000001*/]System.Runtime.CompilerServices.CallConvCdecl/*01000001*/) 
        hello() cil managed
{
  .vtentry 1 : 1
  // Code size       15 (0xf)
  .maxstack  1
  .locals /*11000002*/ ([0] string str)
  IL_0000:  ldnull
  IL_0001:  stloc.0
  IL_0002:  ldstr      "Hello World" /* 70000001 */
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  call       void [mscorlib/*23000001*/]System.Console/*01000003*/::WriteLine(string) /* 0A000002 */
  IL_000e:  ret
} // end of global method hello
您可能可以遵循类似的方法并在元数据表或 IL 反汇编中查找令牌 0x06000094 以找出托管代码中跳转的目的地。
随机观察:
该段.nep似乎意味着“本机入口点”
__mep令牌名称中的前缀可能意味着“托管入口点”。