dotNET 程序文件内主要存储的是 IL 字节码,一般加壳之后,其 IL 字节码会隐藏或屏蔽,而脱壳的关键在于恢复 IL 字节码,进而近似获取程序源代码。
dotNET 程序一般在 JIT 的时候会将 IL 全部或部分解析出来,一般来说不对 token 加密的话,此时JIT的时候,会出现完整的IL。
dotNET JIT 流程大致是:
1
2
3
4
5
6
7
8
9
|
clr!ThePreStub
clr!PreStubWorker
clr!MethodDesc::DoPrestub
clr!MethodDesc::MakeJitWorker
clr!UnsafeJitFunction
clr!CallCompileMethodWithSEHWrapper
clr!invokeCompileMethod
clr!invokeCompileMethodHelper
clrjit!CILJit::compileMethod
|
dotNET 程序在运行的时候,具体到方法执行时,CLR 会为每个方法生成一个 stub,然后调用一堆JIT 函数,生成机器码。这里面关键 JIT 有两个,一个是 DoPrestub 函数,一个是 compileMethod 函数。相对来说,compileMethod 更偏底层。
如果 dotNET 未加壳,那么在 DoPrestub 里就能够获取到 IL ,DoPrestub 的一个参数就是 MethodDesc,也就是方法描述符,通过它就可以获取IL。
但是 dotNET 加壳了,在 DoPreStub 里获取的 MethodDesc ,其找到 IL 是加密的或是错误的。一般壳体会劫持一些 JIT 函数,调用一些解密或恢复函数,进而获取真正的IL,然后再交由所劫持的 JIT 函数去生成机器码,进而执行该方法。
一般壳体不会完整实现更底层的功能,比如如何将每一个IL代码转换成一堆机器码,以及一些代码优化工作,这个工作量太大,而且不太会比原始 JIT 更好,还有可能出现运行错误。
一种策略是,遍历所有的方法,获取方法的 MethoDesc,然后手动触发 DoPrestub,进而触发壳体内部的 IL 解密或恢复函数,获取想要的IL。但是这里存在五个问题:
[注意]看雪招聘,专注安全领域的专业人才平台!
最后于 6天前
被htg编辑
,原因: