.NET函数被反汇编

Rog*_*son 31 .net c# il disassembly

在反汇编.NET函数时,我注意到它们都是以类似于similair的模式开始的.这个初始代码有什么作用?

此代码出现在函数应该执行的实际代码之前.它是某种参数计数验证吗?

FUNC1

private static void Foo(int i)
{
   Console.WriteLine("hello");
}

00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  push        eax 
00000004  mov         dword ptr [ebp-4],ecx 
00000007  cmp         dword ptr ds:[005C14A4h],0 
0000000e  je          00000015 
00000010  call        65E0367F 
//the console writleline code follows here and is not part of the question
Run Code Online (Sandbox Code Playgroud)

FUNC2

static private void Bar()
{
   for (int i = 0; i < 1000; i++)
   {
      Foo(i);
   }
}

00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  push        eax 
00000004  cmp         dword ptr ds:[006914A4h],0 
0000000b  je          00000012 
0000000d  call        65CC36CF 
// the for loop code follows here
Run Code Online (Sandbox Code Playgroud)

FUNC3

private static void Foo()
{
   Console.WriteLine("hello");
}

00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  cmp         dword ptr ds:[005614A4h],0 
0000000a  je          00000011 
0000000c  call        65E3367F 
Run Code Online (Sandbox Code Playgroud)

[编辑]这是对它的正确描述吗?

//fix stackframe
00000000  push        ebp 
00000001  mov         ebp,esp 
//store eax so it can be used locally
00000003  push        eax 
//ensure static ctor have been called
00000004  cmp         dword ptr ds:[006914A4h],0 
//it has been called, ignore it
0000000b  je          00000012
//it hasn't been called, call it now 
0000000d  call        65CC36CF 
Run Code Online (Sandbox Code Playgroud)

要么?

Cod*_*aos 19

这个序言有两个部分.

设置堆栈框架

这会将当前EBP寄存器存储在堆栈中,然后将堆栈指针(ESP)的值分配给EBP.

push        ebp 
mov         ebp,esp
Run Code Online (Sandbox Code Playgroud)

如果存在堆栈中存在局部变量(即寄存器中没有足够的空间可用),则ESP将按其大小移动以构建当前函数的堆栈帧.

在函数结束时,您将看到这些操作相反,因此前一个函数的堆栈帧将被恢复.

EBP应始终指向当前函数
ESP 的堆栈帧的开头到末尾(由于堆栈向下增长,因此在x86上具有较低的地址).

这是常见调用约定的一部分,在抛出异常时需要进行堆栈展开.这不是.net特定的,并且在windows/x86上被大多数调用约定使用.

在设置堆栈帧之后,它通常用于在堆栈上存储一些寄存器.那是因为您可能希望将某些寄存器用作临时变量,但调用约定需要您的函数来保存它们.所以你需要将它们备份到堆栈中.必须保留哪些寄存器以及哪些寄存器可以修改取决于您使用的调用约定.

当提及局部变量在堆栈上,你可以使用[ebp-x]其中ebp点到的StackFrame的开始,x是一个偏移量表示通过StackFrame变量的存储位置.或者,您可以使用[esp+y]堆栈帧末尾的偏移量.

调用静态构造函数/初始化程序

正如danbystrom注意到第二部分很可能是对静态构造函数/初始化程序的调用.由于静态构造函数不是在程序启动时调用,而是在第一次访问时调用,因此抖动无法保证静态构造函数已经执行的每次访问都需要检查它是否已被调用,如果没有,则调用它.

00000004  cmp         dword ptr ds:[006914A4h],0 
0000000b  je          00000012 
0000000d  call        65CC36CF
Run Code Online (Sandbox Code Playgroud)

这就像是if (globalVar!=0) Call Function_65CC36CF.最可能的全局变量指示静态构造函数是否已运行,并且该调用是对静态构造函数的调用.


据我所知,您对拆卸的评论是正确的.


在stackframes上检查这个OldNewThing博客条目:如何挽救损坏的堆栈跟踪:恢复EBP链