首页
社区
课程
招聘
[原创].net下某强壳的不完全分析
发表于: 2006-9-12 22:49 11593

[原创].net下某强壳的不完全分析

2006-9-12 22:49
11593
.net下某强壳的不完全分析

tankaiha[ne365]@ http://vxer.cn
2006-09-12
    其实题目有点偏离内容,因为本文并不是对壳的本身进行深入的分析,而是从另一个角度对其保护和破解进行分析。这个壳是啥偶就不说了,呵呵。(壳作者可是我的偶像)下面开始。

1、壳的保护方式简介
    该壳的网站上已经有很多篇文章介绍过他的方式,但并不深入。(这是当然,因为已经商业化了。)总的来说,.net的运行机制和win32平台下有很多不同,比如.net的PE载入内存后,不是立刻将所有的代码从MSIL编译至native code,而是每运行一个method,编译一个method。当某个method编译过后,它在一定时间内的native code总是存在于内存中,便于下次直接调用。而由于有垃圾收集系统,一段时间不用后,该method所占用的资源又可能被释放。
    该壳便是利用了.net的这种特性,被保护的程序所有的method的代码块大小都被置为0,而真正的代码被壳用多种算法加密保存,但每个method的定义仍在,当jit引擎调用某个method时,被挂钩的程序就是转到壳的解密代码中,将源代码解密完再传给jit。其中包括重建方法表的结构,因为原程序的方法表中代码块的大小是0。这些加密和解密代码都在一个本地dll中,所以该壳的唯一缺点就是被其加密过的程序无法跨平台。其实这一点对共享软件作者来说并不重要,一个程序可以在所有装.net framework的平台上运行就足够了。
    大家都知道.net中有Profiler,它可以JIT开始编译时输出IL代码。如果这样,那不是可以直接用Profiler将IL代码输出吗?非也。壳的作者也在网站上说过,他很了解profiler和jit之间的通讯,可以很容易的避开Profiler的监测。下面,先来看看profiler和jit是怎么通讯的。
TADDR MethodDesc::MakeJitWorker(COR_ILMETHOD_DECODER* ILHeader, DWORD flags)
{
...
...
            if (CORProfilerTrackJITInfo() && !IsNoMetadata())
            {
                {
                   PROFILER_CALL;
                   [COLOR=red]g_profControlBlock.pProfInterface->JITCompilationStarted((ThreadID) GetThread(),(CodeID) this,TRUE);[/COLOR]
                }
                COR_ILMETHOD *pilHeader = GetILHeader();
                new (ILHeader) COR_ILMETHOD_DECODER(pilHeader, GetMDImport(), NULL);
            }
...
...


红色的代码就是JIT通过接口通知Profiler开始JITCompilationStarted,这时我们可以在Profiler中dump内存中的il代码。如果这时IL代码还没有解密呢?(事实也是如此)壳完全可以在发送了该通知后,再调用解密代码,这样,光用Profiler是没法取得程序的源代码的。

例如,对用该壳加密过的某程序用Profiler在JITCompilationStarted里dump得到的内容如下:

JITCompilationStarted:
Class name is:
CFunction name is: x
enter fat codeFlags: FFF
MaxStack: 9600
CodeSize: FFFF07E7
LocalVarSigTok: FFFFFFF
E707FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

FFFF0083E707FFFFFFFFFFFFFFFFFFFFFFFF1A28790000062AFFFF8089E707FFFFFFFFFFFFFFFFFFFFFF8088E707

FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC08BE707FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80B6E707

FFFFFFFFFFFFFFFFFFFFFFFFFFFF03300A002B000000000000002879000006286503000A80ED0B000428F807000A

80EE0B000428F700000A80EF0B000420000000802CE52AFFFF80A6E707FFFF1A28790000062AFFFF80A3E707FFFF

1A28790000062AFFFF80A0E707FFFFFFFFFFFFFF80A1E707FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

FFFFFFFFFFFF40BBE707FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00B7E707

FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0B1E707FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

FF........

不用说了,一堆乱码。下面,我们就开始看怎么dump真正的源代码。

2、取得解密后源代码的思路
    本文的主要内容就是分析怎样取得壳解密过的源代码,而真正完全的脱壳目前还不行,当然,偶觉得也没必要。我们的思路,既然壳挂钩了jit与ee(execute engine)的通讯,我们也可以中断,在jit即将进行编译的一瞬前,代码总是解密过的吧,我们要找到这个断点。
    rotor是源代码是我们了解以上内容的好资料。我们在fjit.cpp里可以看到这个函数:
[COLOR=green]/******************************************************************************

******/
/* jit the method. if successful, return number of bytes jitted, else return 0 */[/COLOR]
FJitResult FJit::jitCompile(
                BYTE ** ReturnAddress,
                unsigned * ReturncodeSize
                )

看名称很像jit的关键函数,只是rotor的代码并不是windows上.net framework的代码,所以jitCompile也不是framework中相对应的函数的名称。想想别的方法。
    mscorjit.dll是jit引擎的核心文件,其中肯定有从ee读入IL的函数。用ida对其进行反编译,当ida提示从网上下载文件的符号时,点确认。仔细搜索一下,有这样一个函数
.text:7906E7F4 private: virtual enum  CorJitResult __stdcall CILJit::compileMethod(class ICorJitInfo *, struct CORINFO_METHOD_INFO *, unsigned int, unsigned char * *, unsigned long *) proc near

compileMethod,光看这个名字就知道他的功能是编译method。看一下输入参数,其中第二个参数是struct CORINFO_METHOD_INFO *
在rotor的源代码中搜索该结构,可以得到如下定义(尽管不知道两个结构是否完全相同,不妨先假设相同,死马当活马医)

struct CORINFO_METHOD_INFO
{
    CORINFO_METHOD_HANDLE       ftn;
    CORINFO_MODULE_HANDLE       scope;
    BYTE *                      ILCode;
    unsigned                    ILCodeSize;

    unsigned short              maxStack;
    unsigned short              EHcount;
    CorInfoOptions              options;
    CORINFO_SIG_INFO            args;
    CORINFO_SIG_INFO            locals;
};

前两个又是指向结构的指针
typedef struct CORINFO_MODULE_STRUCT_*      CORINFO_MODULE_HANDLE;
typedef struct CORINFO_METHOD_STRUCT_*      CORINFO_METHOD_HANDLE;
只是我搜遍了本机和网络也没有找到它们的具体定义,看来又是UnDocumented的。无所谓,关键是第三和第四个成员。ILCode和ILCodeSize,这是不是就是指向了IL代码的内存地址呢?而指向的代码是否又被解过密呢?如果是,我们就可以在这里进行中断,从而输出解密后的代码。

3、调试
    既然已经深入到mscorjit.dll内部,就无需用.net调试了,直接用最熟悉的OllyDbg。先运行被加密过的程序,然后用OD附加到该进程上,接着bp 7906E7F4,很快,OD便中断了。看堆栈值

0012D750        79E9776F  返回到 mscorwks.79E9776F
0012D754        790AF170  mscorjit.790AF170
0012D758        0012D894
0012D75C        0012D920
0012D760        00107210
0012D764        0012D9D4
0012D768        0012D9AC
0012D76C        61893F16
0012D770        00000000
0012D774        0012D920

前两行是jit中的返回地址,原函数中的CORINFO_METHOD_INFO *应该从第四行开始,在0012D920上点右键,选“数据窗口中跟随”,来到该址处。数据窗口中内容如下:

0012D920  28 70 97 01 14 2C 05 01 59 56 90 01 25 00 00 00  (p?,YV?%...
0012D930  08 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00  
....... .......

根据结构定义,红色字体的01905659是IL代码的开始处,而该代码的大小是蓝色显示的0x25。继续,查看01905659处开始的0x25个字节,数据如下:

01905659  72 CE EB 01 70 72 E5 17 00 70 16 1F 40 28 69 01  r坞pr?.p@(i
01905669  00 0A 26 02 7B B9 05 00 04 7E 83 01 00 0A 28 C6  ..&{?.~?..(
01905679  07 00 06 26 2A                                   .&*

这时,偶写的小工具hex2il就派上用场了,对这段数据进行反编译,得到如下代码

l_0000	ldstr	[COLOR=red]<string>7001EBCE[/COLOR]
l_0005	ldstr	[COLOR=red]<string>700017E5[/COLOR]
l_0010	ldc.i4.0	
l_0011	ldc.i4.s	<int8> 40
l_0013	call	<method>0A000169
l_0018	pop	
l_0019	ldarg.0	
l_0020	ldfld	[COLOR=red]<field>040005B9[/COLOR]
l_0025	ldsfld	<field>0A000183
l_0030	call	[COLOR=red]<method>060007C6[/COLOR]
l_0035	pop	
l_0036	ret	

由于是直接编译,没有取得原文件的metadata信息,所以这里<string>、<field>和<method>都是直接用数值表示的。怎么看它们的名称呢?没事,用ildasm打开原程序,dump后的IL里会有这些token相对应的值:

// 7001ebce : (34) L"Thank you for registering XXXXXXXX!"
// 700017e5 : ( 7) L"XXXXXXXX"
.field /*040005B9*/ private class XXXXXXXX.x729558e4a99b7fb0/*02000063*//xdd2eae989d3fc452/*0200014A*/ xa479091352f99870
.method /*060007C6*/ private static pinvokeimpl("user32" lasterr winapi)         
bool  EnumWindows(class CodeLib.x729558e4a99b7fb0/*02000063*//xdd2eae989d3fc452/*0200014A*/ xa479091352f99870, native int x7a5ee4e5d933ebbc) cil managed preservesig

这里还有两个没有解析出来<method>0A000169和<field>0A000183,我暂时也不知道为啥,估计是另外载入的assembly中调用的。其实<method>0A000169应该是MessageBox.show(),就是显示“谢谢注册”的窗口。(也可能是hex2il有BUG
    到此为止,我们已经将源程序的一个method的源代码导出了。而且完全可以写一个程序,将该程序执行过的所有method的源IL都导出。

4、结语
    工作还没有完,一是怎么将源程序所有的method都导出?如果某个method没有执行的话,那jit就永远不会对它编译。二是即使全部导出了,还要将其全部合并为一个PE文件,这不是不可能的,只是工作量非常大。但是,该方法的意义在于,只要得到了关键段(比如注册码比较段的源代码),加上足够的耐心分析,你最终会得到它的注册算法的。
    本文当作抛砖引玉,希望有兴趣的继续深入。欢迎和我就该问题以及所有.net下逆向的话题进行讨论!


btw:经官方同意,做一小广告
对.net逆向有一定程度了解(要是一点都不了解的话,建议先看看书呵,就不要急着加了),而又苦于找不到人讨论的,可以发送邮件至
dotnetreverseteam@126.com,主要介绍一下你对.net逆向了解的程度和主攻方向.然后我们会将你吸收入DotnetReverseTeam的QQ群。在那里,你会找到许多志同道合的兄弟。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (14)
雪    币: 538
活跃值: (32)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
第一个来学习
2006-9-12 22:56
0
雪    币: 44229
活跃值: (19955)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
3
过阵子是要准备熟悉一下.net,到时找tankaiha麻烦
2006-9-12 22:58
0
雪    币: 2384
活跃值: (766)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
4
什么都不说了,先收藏起来先(以防止。。。)。
2006-9-12 23:03
0
雪    币: 70
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
只能膜拜先~~~
2006-9-13 11:54
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
tankaiha
大哥,你写的文章是精品啊,和你的CCL一样也是精品,那你人也肯定是精品
2006-9-13 21:15
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
挺好啊,学习中,
顶。。。。。。。。。。。。。
2006-9-13 23:07
0
雪    币: 230
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
kanxue大侠可以考虑出一本.net加解密方面的书。。。
2006-9-13 23:30
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
9
最初由 baibai 发布
tankaiha
大哥,你写的文章是精品啊,和你的CCL一样也是精品,那你人也肯定是精品


hmx很帅的,且1.83m
2006-9-14 13:02
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
拜一下,很有启发。
2006-9-14 13:04
0
雪    币: 258
活跃值: (230)
能力值: ( LV12,RANK:770 )
在线值:
发帖
回帖
粉丝
11
最初由 nbw 发布
hmx很帅的,且1.83m


哟1点83
文章不错,
2006-9-14 20:50
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
刚刚在调试板块看完又在脱壳看大大的net文章.....然后回过头来看看自己的VC6.0....
2006-9-15 08:09
0
雪    币: 175
活跃值: (2331)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
.net资料,喜欢收藏!
2006-9-15 08:38
0
雪    币: 146
活跃值: (33)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
14
最初由 nbw 发布
hmx很帅的,且1.83m


啊!
2006-9-17 17:38
0
雪    币: 211
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15

OTL
2006-9-24 15:04
0
游客
登录 | 注册 方可回帖
返回
//