[原创]使用OllyDbg调戏.NET 4.0的WinForms应用程序
最近看到vxk老师的“调戏”很火,小弟也来高攀起个调戏吧
很多人对OD调试C#程序可以说想都不想,觉得这不可能的,不过对简单的.NET程序验证,OD还是可以上马的。
而且如果.NET程序混淆过了,而你想做大事,怎么办?此时OD还真可以帮忙。
下面有一个C#应用程序:WindowsFormsApplication1
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
[DllImport("kernel32.dll")]
public static extern int GetCurrentProcessId();
public Form1()
{
InitializeComponent();
}
[B] private void button1_Click(object sender, EventArgs e)
{
if (GetCurrentProcessId() != 1234)
MessageBox.Show("No");
else
MessageBox.Show("Yes");
}[/B]
}
}可以看到其调用了一个API来验证,我们编译后,打开OD,载入这个.NET的exe。
(注意,在.NET 4.0中,OD一载入.NET编译的程序,当mscoree被载入后,程序会自动跑到CorExeMain并运行起来,不会停在入口点,此时如果想从clr!_CorExeMain开始调试的话,需要设置停在系统断点)
我们看到它已经运行起来了,此时啥也不管,输入bp GetCurrentProcessId,下断,然后点button1。
我们看到断了下来:

我们在堆栈的call上回车,直接来到return的地方,可以看到下面都是一片0,说明这是一个clr实时JIT生成的thunk call:

什么是C#的thunk call,这个东西其实是clr中的一段代码:

当要执行C#代码的时候,JIT会把C#代码在内存中翻译成本机代码,然后用这种thunk call来jmp到本机代码。
说完thunk call,我们接着把这个call跟到ret,发现其带着GetCurrentProcess的返回值来到了另一个call:

大家懂了。。。把JE改JMP就好了,这样Yes就出来了。。

第二个C#程序:WindowsFormsApplication2
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[B] private void button1_Click(object sender, EventArgs e)
{
Random r = new Random();
if (textBox1.Text != r.Next().ToString())
MessageBox.Show("No");
else
MessageBox.Show("OK");
}[/B]
}
}这个是生成一个随机数然后判断你在文本框里面输入的文本是否等于随机数。。。一看就知道OK是永远不会弹出的,这个要如何做呢。
其实很简单,MessageBox.Show本质上还是user32的MessageBox,我们打开OD载入,然后bp MessageBoxW。
点按钮,可以看到断下来了:

可以看到是No,我们直接把堆栈窗口滚下来,还记得上面的thunk call么,我们知道thunk call都是动态的内存,所以我们在堆栈上看到最近的这样一个call类库的call时:

跟进去:

我们在这个call的头F2,再点一次按钮,断下了,一步步跟。。。
我们注意到JNE上面有一个call,call上面是对ecx和edx的赋值,是不是想起了什么?呵呵,我们在ecx上右键选择定位数据窗口:

这下大家懂了吧,呵呵。

