-
-
[原创]垃圾代码发生器[设计+源码]
-
发表于:
2011-3-11 17:53
22170
-
很久没有来了.今天来冒个泡,花3天写了个不成熟的东西,与大家分享.
主要介绍个垃圾代码发生器,由于时间短,而且本身这种设计的限制,所以不可能有多么的优秀!
反正闲着也是闲着,就当是玩儿了,呼呼
本身技术很简单,主要就是编码
我主要是递归生成的,比较绕,好技术不如烂笔头,写写画画,最终还是可以理顺的。
修正了几个错误的地方,重新发个可编译的稳定版本
正题..................................
垃圾发生器设计方案
发生器组成---
垃圾代码生成器 --------------------------- 垃圾代码插入器
垃圾代码生成器原理---
垃圾代码生成器使用两层模板,内模板和外模板
可以配置生成器来选择把内还是外模板作为生成主类型
同时在内外模板的作用下形成的框架中会插入随机生成的各种字节长度的指令
通过配置和丰富内外模板以及随机的范围可以实现不同程度的垃圾指令
外模板:(示例1)
push ebp 1
nop 1
nop 1
mov ebp,esp 2
inc ecx 1
nop 1
push reg 1
nop 1
nop 1
pop reg 1
nop 1
pop ebp 1
loop somewhere
someshere:
nop 1
内模板:(示例2)
push reg(1)
call addr(5)
...
...
....
add esp,4(3)/pop reg(1)
pop reg(1)
算法:
1>选择主类型(三种:内模板型,外模板型,nop型)
说明:一般是以外模板为主类型
2>根据主类型确定调用的主例程
类似GenJunkCode(外模板)
1.从现有的外模板里面选出长度小于等于需求长度的模板总数和各自的长度
2.通过一个随机数确定使用这些选出的外模板中的哪一个来生成
3.在输出缓冲中写入外模板规定的指令
4.如果选取的外模板的长度小于需求长度,那么写完后必然有剩余空间
剩余空间的填充的话调用类似GenLastSpace()的函数
类似GenJunkCode(内模板)
1.生成一个随机数,来决定选择现有的哪个模板开始填充
内模板一般比较简单
而且在中间一般会留有空间,这些空间也必须填充
2.选取好内模板后从第一条以此填充,遇到剩余空间的时候调用类似GenLastSpace()的函数,知道填充完毕
类似GenLastSpace()
1.判断传递进来的剩余空间的大小
2.剩余空间小于5的话,生成一个随机数,来决定是直接nop还是随机填充
如果是直接nop的话,那就填充剩余空间个0x90
如果是随机填充的话,根据剩余指令的长度,来随机生成对应长度的指令(必然有5种可能)
3.剩余空间如果大于5的话,那么也得分两种情况
如果是在GenJunkCode(内模板)中调用到GenLastSpace()例程的时候,那么递归调用GenJunkCode(外模板)
如果是在GenJunkCode(外模板)中调用到GenLastSpace()例程的时候,那么递归调用GenJunkCode(内模板)
这样就形成了交叉的产生以不同类型为主类型的垃圾代码
3>循环递归完成上述的调用后填充最终完毕
垃圾代码插入器原理----
将传入的X条指令平均的插入在指定长度的垃圾代码中(反之同理)
这里采用完全的平均插入
由于并不能完全等大小的平分代码区域,所以必然在最后有若干字节的剩余空间
对于剩余空间必须加以处理
——————————
| |
| | ______________________
| 代码区域 | | stub区域 |
| | |______________________|
| |
|___________ ___|
算法:
1>选取stub(也就是选取现有的待处理代码 假设这些代码有很多,而且已经编号了)
生成一个随机数来选取要用哪个stub
确定stub后对其进行填充(这个不能外部填充,是定死的,只能在编码中直接添加)
同时会获取该stub的大小,指令条数已经每条指令的长度信息
2>获取全局信息
传入的参数----
M-代码区域大小
N-stub区域的大小 (上面一步会获取到这个信息)
算出的信息存放在一个GLOBAL_INFO的结构体里面
这个结构体为
typedef struct _GLOBAL_INFO
{
__integer CodeBuffSize; M
__integer StubBuffSize; N
__integer JunkSize; Z
__integer BlockNum; N'
__integer PerBlockSize; Q
__integer s; S
}GLOBAL_INFO,*PGLOBAL_INFO;
Z=M-N
N'=N+1
Q=Z/N'(取整数)
S=Z-Q*N'
3>调用垃圾代码生成器的借口函数来生成一段Q大小的垃圾代码。在代码区域的起始开始填充,填充完毕后调整指针,接着根据第一步获取的信息拷贝stub,完毕后调整指针
4>循环上述3>过程知道循环计数达到N'时退出
5>检测是否存在剩余空间
判断剩余空间的大小,如果小于5的话直接填充nop
如果大于5的话,可以继续调用垃圾代码生成器的借口函数,进入其中进行生成(要求代码生成器足够的稳定才能这样嵌套的调用)
定义的结构体:
typedef struct _JCE_CONFIG
{
__integer JunkSize;
__integer JunkStyle;
__memory InsertAddr;
__memory OutJunkAddr;
__bool Direct;
__bool FillModelLastSpaceByNop;
}JCE_CONFIG,*PJCE_CONFIG;
typedef struct _JCE_RUNTIME
{
__memory OriOutAddr;
__memory CurAddr;
__integer LastSpace;
__integer CurDecSize;
__integer TtoalSpace;
}JCE_RUNTIME,*PJCE_RUNTIME;
typedef struct _GLOBAL_INFO
{
__integer CodeBuffSize;
__integer StubBuffSize;
__integer JunkSize;
__integer BlockNum;
__integer PerBlockSize;
__integer s;
}GLOBAL_INFO,*PGLOBAL_INFO;
typedef struct _STUB_INFO
{
__integer StubSize;
__integer StubInsNum;
__memory StubContent1[MAX_STUB1_INS_NUM];
__memory StubContent2[MAX_STUB2_INS_NUM];
__memory StubContent3[MAX_STUB3_INS_NUM];
}STUB_INFO,*PSTUB_INFO;
实现的函数:
__void GenJunk(__memory _code_buff,__integer _code_size,__integer _junk_style);
__void SelectStub(PSTUB_INFO _si,__integer _dice);
__void JceAttach(__memory _code_buff,__integer _code_size);
__void CopyStub(__memory _code_buff,__memory _stub_code,__integer _copy_len);
GLOBAL_INFO GetGlobalInfo(__integer _code_size,PSTUB_INFO _si);
__void GneRandomInsByLen(PJCE_RUNTIME _jt);
__void GenRandomIns(PJCE_RUNTIME _jt);
__memory _fill_opcode(__integer _num,__memory _write_to,__byte _opcode,__bool _rand);
__integer _select_small_equ(__integer *InPutArry,__integer *OutPutArry,__integer CmpNum);
__integer CalcLastSpace(__integer JunkCodeSize,__integer ModelSize);
__void InitRuntime(PJCE_RUNTIME _jt,PJCE_CONFIG _jc);
__void InitGenerater(__integer _junk_code_size,__integer _junk_code_style,__memory _junk_insert_addr,__memory _junk_out_addr,__bool _direct);
__void ReleaseGenerater(PJCE_CONFIG _jc);
__integer GenJunkCode(PJCE_CONFIG _jc);
__bool GenJunkByRand(PJCE_CONFIG _jc);
__bool GenJunkByModel(PJCE_CONFIG _jc);
缺陷:
1>垃圾代码生成器稳定性还没有测试,本身没有容错考虑
比如生成一段垃圾代码
Push ebp
Mov ebp,esp
....
...
Add eax,eax
-------------------------- 垃圾代码的结尾
--------------------------真实代码的开始
Test ebx,ebx
本身在代码区域里面,我们的垃圾代码和真实代码都是以16进制的数字进行拷贝的,页最终以十六进制链接在一起,但是有一种情况就是:在分开的时候,垃圾代码以A指令结尾,真正代码以B指令开头,如上图
但是他们的十六进制合在一起的时候可以会在拼接处形成C指令 这个时候上下两端代码同时遭到破坏。
因此需要在自己构造stub的时候再每个衔接处处理
2>插入在同一个代码区域内的X段垃圾指令之间没有跳转进行联系,相对显示是隔离开的,这样的迷惑效果不好。
4>当前的生成的垃圾指令主要以跳转为主,随机化的指令较少,只有在递归中空间小于5的时候才有机会出现随机化的指令
附加说明:由于这个文档写的稍微早一点,所以有些结构体的定义等信息已经修改了,但是总体不影响算法的描述,具体的改动直接看代码!
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)