淘淘乐网站建设,办公用品网站建设可行性分析,百度宣传广告要多少钱,新媒体营销总结偶然翻了一下手机日历#xff0c;原来今天是夏至啊#xff0c;时间过的真快。ISCC的比赛已经持续了2个多月了#xff0c;我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦#xff0c;但感觉还是很幸运的#xff0c;能在大三的时候遇到ISCC#xff0c;不管怎样…偶然翻了一下手机日历原来今天是夏至啊时间过的真快。ISCC的比赛已经持续了2个多月了我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦但感觉还是很幸运的能在大三的时候遇到ISCC不管怎样对我来说都会是一个很好的锻炼机会。 在做综合关的逆向破解的题目遇到了很多蛋疼的问题磕磕碰碰把《加密与解密》看完了。还是老习惯把这1个多星期以后学到的想到的做一个总结希望能有一个思想上的提高也希望能对其他人有一个借鉴的效果吧。这里想起lenus大神的一句话 Hacker的精神里面除了学习learn的第一精神以外,还应该是共享(share)的精神。 好废话不多说开始吧。 1. 逆向破解 一开始接触逆向我直接是使用的一些加壳脱壳工具都是鼠标点一下就出来了这段时间深入了解了逆向的原理之后我感觉逆向是一个综合性很强的技术中间还需要windows编程PE结果汇编等知识。 对于脱壳我的理解是脱壳不意味着它字面上的意思把外壳直接拿掉然后就扔掉像吃水果一样脱壳本质上是一个高级的crack技术也就是绕过破解。 这是一张关于壳的图示 而我们不管用lordPE, procDump, 还是手工脱壳也好其实本质上就是要改变程序的执行流让程序跳过头部实际中不一定是头部这里只是逻辑上的的一段壳代码而直接来到原程序的入口代码处也就是常说的OEP那问题就来了那脱壳就这么简单 当然不是我个人感觉脱壳并不仅仅是改变程序执行流这么简单因为被加过壳的程序往往IAT重定位表节区都被加密压缩处理过了。如果你直接强行跳转过来程序也是不能执行的。所以网上常说的找OEP的原理就在这里。为什么要找OEP呢其实本质上来说这并不是最重要的不要被这些形式上的东西框住了思维我们从原理上思考一个程序要运行无非需要几种东西 1. 可以执行的机器码 2. IAT 3. 重定位表DLL 4. 资源代码不太重要就是了因为并不影响逆向的结果 转换了思维之后我就豁然开朗了我们要做的就是找到代码中的某一行恰好已经全部完成了代码的解压缩和解密IAT的重写重定位表的重写做好这些事后我们就可以dump下来了至于是不是OEP其实不是很重要所谓的找OEP是因为一般情况下在OEP的时候恰好都满足了上面的条件而且也比较好找到所以OEP是dump的首选如果你理解了原理这么做也没有错。 第二点就是为什么要用ImportREC来重建IAT表呢它的原理又是什么呢 这里首先要从加壳的原理说起不管你是UPX压缩壳ASProtect穿山甲加密壳还是VMP虚拟机壳...基本上来说都会破坏原本的IAT将原本的IAT移到一个新的节区里面并加密等处理然后构建自己的IAT表并修改PE头。为什么要这么做呢 因为壳必须保证它能调用到自己需要的函数但是原程序并不能保证这点所以壳必须自己构造自己的IAT三剑客 调用LoadLibrary将dll文件映射到调用进程的地址空间中调用GetModualHandle获得dll模块句柄调用GetProcAddress获取输入函数的地址 一般壳程序都会构造这三个API然后重建自己的IAT表这样壳程序就能保证调用到自己需要的所有winAPI了。 而我们脱壳的是内存中的映像即使这时候原程序的IAT已经恢复过来了解压缩解密但是位置已经变了原程序无法直接调用了。而ImportREC的作用就是找到这里API对用RVA然后在一段空的地方重建这些结构逆向构造出一个IAT出来然后修改PE头完成IAT的修复。明白了原理自己手工修复IAT也是一样的。 修复重定位表和资源表的原理也是一样的就不在详述了。 下面我们通过一个dump实例的编程过程来深刻的理解一个dump的思想。 接下来的程序是我们对看雪上的一篇帖子的学习笔记是lenus大神的脱壳教程我这里就当是做一个学习笔记。 一dump小程序的目标 对于dump来说他的英文翻译就是“转存”。也就是说把内存中或者其他的输入转存到另一个位置当然对于我们现在说的dump就是把内存中运行的PE进程的数据从内存中抓取出来然后在用文件的形式保存下来。 根据上面的分析我们基本上得到了一个这样的思维。Dump程序要做的事分几个基本的步骤 1 在系统中找到目标进程2 在进程中确定进程的大小imagesize3 把进程中的数据保存到文件 Code resource.h #define ID_FLESH 2#define IDD_DIALOG1 101#define ICO_MAIN 103#define IDC_PROCESS 1028#define IDC_CORRECT 1033// Next default values for new objects// #ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE 105#define _APS_NEXT_COMMAND_VALUE 40001#define _APS_NEXT_CONTROL_VALUE 1034#define _APS_NEXT_SYMED_VALUE 101#endif#endif #include windows.h#include tlhelp32.h#include resource.hBOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);BOOL GetProcessListFunc(HWND hDlg,HWND hWindList); // 列出各个进程的函数刷新时也用到LPCTSTR SaveAsFunc(HWND hDlg); //通用对话框函数BOOL DumpFunc(HWND hDlg,HWND hWindList); // 主要的dump函数调用其他的小功能函数实现其功能BOOL CreateDumpFile(HWND hDlg,LPCTSTR Dump_Name,HGLOBAL hMem); //生成dump文件函数把dump的东西写到磁盘上HGLOBAL ReadProcess(HWND hDlg,DWORD IDProcess); //读取目标进程空间放置到本空间申请的堆中int GetSizeOfImage(HWND hDlg,DWORD IDProcess); // 获取pe文件的SizeOfImageBOOL CheckPEFunc(HWND hDlg,HANDLE hProcess); //检查pe文件的完整性BOOL CorrectSizeFunc(HWND hDlg,HWND hWindList); //纠正文件的大小LPCTSTR GetFilePath(HWND hDlg,DWORD IDProcess);//获取目标exe的绝对路径BOOL ModifySectionFunc(HWND hDlg,LPCTSTR Dump_Name);//修改文件的节表使其RARVA RSRVSBOOL CopyThePEHead(HWND hDlg,LPCTSTR Dump_Name); //把原来PE文件的头部复制到dump文件中全局变量/int sizeoffile0;int sizeofimage0; //当使用了CorrectSizeFunc后这个有了具体数值就不需要再次获取了int BaseAddress0x400000; DWORD ID0; //这个是用来控制进程的切换的///int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ DialogBoxParam (hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,DlgProc,(LPARAM)hInstance); return TRUE;}BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){ static HINSTANCE hInstance; static HWND hWindList; switch (message) { case WM_CLOSE: EndDialog (hDlg, 0) ; return TRUE ; case WM_INITDIALOG : hInstance (HINSTANCE) lParam; SendMessage(hDlg,WM_SETICON,ICON_BIG,(LPARAM)LoadIcon(hInstance,MAKEINTRESOURCE(ICO_MAIN))); hWindList GetDlgItem(hDlg,IDC_PROCESS); if(!GetProcessListFunc(hDlg,hWindList)) { MessageBox(hDlg,TEXT(Fail to get the process),TEXT(Sorry),MB_OK | MB_ICONSTOP); EndDialog(hDlg,0); } return TRUE ; case WM_COMMAND : switch (LOWORD (wParam)) { case IDOK : DumpFunc(hDlg,hWindList); return TRUE ; case ID_FLESH: if(!GetProcessListFunc(hDlg,hWindList)) { MessageBox(hDlg,TEXT(Fail to get the process),TEXT(Sorry),MB_OK | MB_ICONSTOP); EndDialog(hDlg,0); } return TRUE; case IDC_CORRECT: if(!CorrectSizeFunc(hDlg,hWindList)) MessageBox(hDlg,TEXT(The correct size function is faile...),TEXT(Fail...),MB_OK | MB_ICONWARNING); return TRUE; } break ; } return FALSE ;}BOOL GetProcessListFunc(HWND hDlg,HWND hWindList){ //此函数是进程列表的作用在此不作过多介绍 HANDLE hProcessSnap NULL; PROCESSENTRY32 pe32 {0}; SendMessage(hWindList,LB_RESETCONTENT,0,0); pe32.dwSize sizeof(PROCESSENTRY32); hProcessSnap CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap INVALID_HANDLE_VALUE) return FALSE; if (!Process32First(hProcessSnap, pe32)) { CloseHandle (hProcessSnap); return FALSE; } do { WPARAM tmp(WPARAM)SendMessage(hWindList,LB_ADDSTRING,0,(LPARAM)pe32.szExeFile); SendMessage(hWindList,LB_SETITEMDATA,tmp,(LPARAM)pe32.th32ProcessID); } while (Process32Next(hProcessSnap, pe32)); CloseHandle (hProcessSnap); return TRUE;}BOOL DumpFunc(HWND hDlg,HWND hWindList){ HGLOBAL hMem; LPCTSTR Dump_NameNULL; //感觉有点问题这个只是指针没有开辟足够的空间。 //从数组规定好的到指针未规定好的就可以 //从指针到数组就不可以 WPARAM tmp(WPARAM)SendMessage(hWindList,LB_GETCURSEL,0,0); if (tmpLB_ERR) { MessageBox(hDlg,TEXT(Please choose a process...),TEXT(oh...no,no,no...),MB_OK); return FALSE; } DWORD IDProcessSendMessage(hWindList,LB_GETITEMDATA,tmp,0); //获得此列单里面的进程ID IDIDProcess; hMemReadProcess(hDlg,IDProcess); if(hMem) //如果返回的hMen不正确说明没有正确的申请到空间 { if(sizeoffile!0) //没有大小的dump 是没有意义的 { Dump_NameSaveAsFunc(hDlg); //要保存的文件名 if(Dump_Name) //如果得到的文件名是空就不继续执行 { CreateDumpFile(hDlg,Dump_Name,hMem); //把数据写入文件中 GlobalFree(hMem); //资源是可贵的释放空间 } } } return TRUE;}LPCTSTR SaveAsFunc(HWND hDlg){ //获取你要保存的文件名默认为dumped.exe HANDLE hFile; static char szFileName[MAX_PATH]dumped; OPENFILENAME stOF{0}; stOF.hwndOwnerhDlg; stOF.lStructSizesizeof(stOF); stOF.lpstrFilter*.*; stOF.lpstrDefExtexe; stOF.nMaxFileMAX_PATH; stOF.lpstrFileszFileName; if(!GetSaveFileName(stOF)) return FALSE; char szBuffer[100]; char szMsg[]%s 已存在。要替换它吗; wsprintf(szBuffer,szMsg,szFileName); hFileCreateFile(szFileName,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile ! INVALID_HANDLE_VALUE) { if(IDNOMessageBox(hDlg,szBuffer,TEXT(另存为),MB_YESNO | MB_ICONWARNING)) { CloseHandle(hFile); return FALSE; } } CloseHandle(hFile); return szFileName;}BOOL CreateDumpFile(HWND hDlg,LPCTSTR Dump_Name,HGLOBAL hMem){ //创建一个新的dump文件 HANDLE hFileCreateFile(Dump_Name,GENERIC_WRITE | GENERIC_READ,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if(hFileINVALID_HANDLE_VALUE) { MessageBox(hDlg,TEXT(Maybe you have alreadly had a this name file:(), TEXT(Cant create a file),MB_OK | MB_ICONWARNING); GlobalFree(hMem); return FALSE; } int NumberOfBytesWritten; WriteFile(hFile,hMem,sizeoffile,(LPDWORD)NumberOfBytesWritten,NULL); //注意这个函数第三个参数是必要的 CloseHandle(hFile); if(!CopyThePEHead(hDlg,Dump_Name)) { //复制PE头 MessageBox(hDlg,TEXT(复制PE头失败了),TEXT(失败了),MB_OK | MB_ICONWARNING); } if(!ModifySectionFunc(hDlg,Dump_Name)) { //节表对齐 MessageBox(hDlg,TEXT(修改节表失败了),TEXT(失败了),MB_OK | MB_ICONWARNING); } MessageBox(hDlg,TEXT(文件已经dump成功),TEXT(LenusExeDump),MB_OK | MB_ICONINFORMATION);//胜利的号角 return TRUE;}HGLOBAL ReadProcess(HWND hDlg,DWORD IDProcess){ //此函数是读取目标进程的空间并把他写入到自己内存空间里面的一个内存块中 HANDLE hProcessOpenProcess(PROCESS_ALL_ACCESS,0,IDProcess);//使用上面获得的进程id if(!hProcess) { MessageBox(hDlg,TEXT(I cant open the process:(),TEXT(oh my god..),MB_OK); return FALSE; } if(sizeofimage0 || ID!IDProcess) //当更换当前的进程或者没有使用修正的功能的时候需要重新的获取 //由于不知道在更换选项的时候会发出什么消息所以只能这么干 so foolish { sizeofimageGetSizeOfImage(hDlg,IDProcess); } if(!sizeofimage) { return FALSE; } //为了以防万一让sizeofimage增加一个文件对齐度。 if(!(sizeofimage%0x1000)) //如果是文件对齐度的整数倍的时候就不处理 sizeoffilesizeofimage; else sizeoffile(sizeofimage/0x10001)*0x1000; //如果不是就增加一个文件对齐度 //申请一个文件空间的内存块 static HGLOBAL hMem0; hMemGlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,sizeoffile); if(!hMem) { MessageBox(hDlg,TEXT(I think i have enough space to get!:(),TEXT(Wrong!!!),MB_OK | MB_ICONSTOP); return FALSE; } //将这个pe文件在内存中的大小全部读到申请的块中 DWORD NumberOfBytesReadorWrite; if(!ReadProcessMemory(hProcess,(LPCVOID)BaseAddress,hMem,sizeofimage,NumberOfBytesReadorWrite)) { MessageBox(hDlg,TEXT(I cant read the process:(),TEXT(oh my god..),MB_OK); return FALSE; } CloseHandle(hProcess); //有开始就有关闭 Sleep(200); //等待一会 return hMem;}int GetSizeOfImage(HWND hDlg,DWORD IDProcess){ //这个函数的作用是获取SizeOfImage的数值 //当函数执行失败返回的是0 //成功返回的是非0 HANDLE hModuleSnap NULL; MODULEENTRY32 stModE {0}; stModE.dwSize sizeof(MODULEENTRY32); hModuleSnap CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,IDProcess); //快照对本进程中所有的模块进行snap if (hModuleSnap INVALID_HANDLE_VALUE) { MessageBox(hDlg,TEXT(The Module snapshot cant get!),TEXT(Error!),MB_OK | MB_ICONSTOP); return FALSE; //返回0 } if (!Module32First(hModuleSnap, stModE)) { MessageBox(hDlg,TEXT(The Module32First cant work!),TEXT(Error!),MB_OK | MB_ICONSTOP); CloseHandle (hModuleSnap); return FALSE; } CloseHandle (hModuleSnap); return stModE.modBaseSize;//初始化为0}BOOL CheckPEFunc(HWND hDlg,HANDLE hProcess){ //检查pe文件检查两个标志 //如果不是pe文件那么会迫使GetSizeOfImage直接返回 //下面不是重点所以不介绍了 int BaseAddress0x400000; IMAGE_DOS_HEADER DosHead; _IMAGE_NT_HEADERS NtHead; if(!ReadProcessMemory(hProcess,(LPCVOID)BaseAddress,DosHead.e_magic,2,NULL)) { MessageBox(hDlg,TEXT(I cant read the IMAGE_DOS_SIGNATURE:(),TEXT(oh my god..),MB_OK); return FALSE; } if(DosHead.e_magic ! IMAGE_DOS_SIGNATURE) { return FALSE; } if(!ReadProcessMemory(hProcess,(LPCVOID)(BaseAddress0x3c),DosHead.e_lfanew,4,NULL)) { MessageBox(hDlg,TEXT(I cant read the e_lfanew:(),TEXT(oh my god..),MB_OK); return FALSE; } if(!ReadProcessMemory(hProcess,(LPCVOID)(BaseAddressDosHead.e_lfanew),NtHead.Signature,4,NULL)) { MessageBox(hDlg,TEXT(I cant read the e_lfanew:(),TEXT(oh my god..),MB_OK); return FALSE; } if(NtHead.Signature ! IMAGE_NT_SIGNATURE) { return FALSE; } return TRUE; }BOOL CorrectSizeFunc(HWND hDlg,HWND hWindList){ //函数能获取文件的PE头部的SizeOfImage作为正确的SizeOfImage LPCTSTR File_NameNULL; WPARAM tmp(WPARAM)SendMessage(hWindList,LB_GETCURSEL,0,0); if (tmpLB_ERR) { MessageBox(hDlg,TEXT(Please choose a process...),TEXT(oh...no,no,no...),MB_OK); return FALSE; } DWORD IDProcessSendMessage(hWindList,LB_GETITEMDATA,tmp,0); //获得此列单里面的进程ID IDIDProcess;//全局变量ID的作用是控制在不同的进程的切换 File_NameGetFilePath(hDlg,IDProcess); if(!File_Name) return FALSE; //打开文件 HANDLE hFile; hFileCreateFile(File_Name,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if (hFile INVALID_HANDLE_VALUE ) { return FALSE ; } //创建文件映射内核对象 HANDLE hMapping; hMapping CreateFileMapping (hFile, NULL, PAGE_READONLY,0,0,NULL); if (hMapping NULL ) { CloseHandle (hFile ) ; return FALSE; } //创建文件视图 LPVOID ImageBase ; ImageBase MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0) ; if (ImageBase NULL) { CloseHandle (hMapping) ; return FALSE; } //下面的代码就是从文件的PE头找到SizeOfImage的 PIMAGE_DOS_HEADER DosHead NULL ; PIMAGE_NT_HEADERS32 pNtHeader NULL ; PIMAGE_FILE_HEADER pFileHeader NULL ; PIMAGE_OPTIONAL_HEADER pOptionalHeader NULL ; PIMAGE_SECTION_HEADER pSectionHeader NULL ; DosHead(PIMAGE_DOS_HEADER)ImageBase; pNtHeader ( PIMAGE_NT_HEADERS32 ) ((DWORD)ImageBase DosHead-e_lfanew ) ; pOptionalHeader pNtHeader-OptionalHeader; sizeofimage(int)pOptionalHeader-SizeOfImage; //找到了以后输出结果 char szBuffer[100]; char szMsg[]原来的image size是%08X\n修整的image size是%08X; wsprintf(szBuffer,szMsg,GetSizeOfImage(hDlg,IDProcess),sizeofimage); MessageBox(hDlg,szBuffer,TEXT(纠正结果),MB_OK ); CloseHandle (hMapping); CloseHandle (hFile) ; Sleep(200); return TRUE; }LPCTSTR GetFilePath(HWND hDlg,DWORD IDProcess){ //此函数获得目标进程的绝对路径 //如果获取失败返回NULL HANDLE hModuleSnap NULL; MODULEENTRY32 a {0}; a.dwSize sizeof(MODULEENTRY32); hModuleSnap CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,IDProcess); //快照对本进程中所有的模块进行snap if (hModuleSnap INVALID_HANDLE_VALUE) { MessageBox(hDlg,TEXT(The Module snapshot cant get!),TEXT(Error!),MB_OK | MB_ICONSTOP); return FALSE; //返回0 } if (!Module32First(hModuleSnap, a)) { MessageBox(hDlg,TEXT(The Module32First cant work!),TEXT(Error!),MB_OK | MB_ICONSTOP); CloseHandle (hModuleSnap); return FALSE; } CloseHandle (hModuleSnap); return a.szExePath;}BOOL ModifySectionFunc(HWND hDlg,LPCTSTR Dump_Name){ //此函数的将修改dump下来的exe使其RARVA RSRVS //首先是打开dump文件 HANDLE hFileCreateFile(Dump_Name,GENERIC_WRITE | GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFileINVALID_HANDLE_VALUE) { MessageBox(hDlg,TEXT(I can open the dump file...),TEXT(Error!!),MB_OK | MB_ICONWARNING); return FALSE; } //下面移动到节表前面 IMAGE_DOS_HEADER myDosHeader; DWORD NumberOfBytesReadorWrite; ReadFile(hFile,(LPVOID)myDosHeader,sizeof(IMAGE_DOS_HEADER),NumberOfBytesReadorWrite,NULL); SetFilePointer(hFile,myDosHeader.e_lfanewsizeof(DWORD),NULL,FILE_BEGIN); IMAGE_FILE_HEADER myNtHeader; ReadFile(hFile,(LPVOID)myNtHeader,sizeof(IMAGE_FILE_HEADER),NumberOfBytesReadorWrite,NULL); int nSectionCount; nSectionCount myNtHeader.NumberOfSections; // 保存Section个数 // 过了IMAGE_NT_HEADERS结构就是IMAGE_SECTION_HEADER结构数组了注意是结构数组有几个Section该结构就有几个元素 // 这里动态开辟NumberOfSections个内存来存储不同的Section信息 IMAGE_SECTION_HEADER *pmySectionHeader (IMAGE_SECTION_HEADER *)calloc(nSectionCount, sizeof(IMAGE_SECTION_HEADER)); SetFilePointer(hFile,myDosHeader.e_lfanew sizeof(IMAGE_NT_HEADERS),NULL,FILE_BEGIN); ReadFile(hFile,(LPVOID)pmySectionHeader,sizeof(IMAGE_SECTION_HEADER)*nSectionCount, NumberOfBytesReadorWrite,NULL); //移动回到节表的开始准备写入 SetFilePointer(hFile,myDosHeader.e_lfanew sizeof(IMAGE_NT_HEADERS),NULL,FILE_BEGIN); for (int i 0; i nSectionCount; i, pmySectionHeader) { //将RARVA RSRVS pmySectionHeader-SizeOfRawDatapmySectionHeader-Misc.VirtualSize; pmySectionHeader-PointerToRawDatapmySectionHeader-VirtualAddress; //将修改好的数值写回 WriteFile(hFile,(LPVOID)pmySectionHeader,sizeof(IMAGE_SECTION_HEADER),NumberOfBytesReadorWrite,NULL); } // 恢复指针 pmySectionHeader -nSectionCount; if (pmySectionHeader ! NULL) // 释放内存 { free(pmySectionHeader); pmySectionHeader NULL; } // 最后不要忘记关闭文件 CloseHandle(hFile); return TRUE;}BOOL CopyThePEHead(HWND hDlg,LPCTSTR Dump_Name){ //此函数的作用是将原来PE文件的PE头部完整的copy到dump文件中 HANDLE hFileCreateFile(GetFilePath(hDlg,ID),GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFileINVALID_HANDLE_VALUE) { MessageBox(hDlg,TEXT(I can open the object file...),TEXT(Error!!),MB_OK | MB_ICONWARNING); return FALSE; } //下面移动到节表前面 IMAGE_DOS_HEADER myDosHeader; DWORD NumberOfBytesReadorWrite; ReadFile(hFile,(LPVOID)myDosHeader,sizeof(IMAGE_DOS_HEADER),NumberOfBytesReadorWrite,NULL); SetFilePointer(hFile,myDosHeader.e_lfanewsizeof(DWORD),NULL,FILE_BEGIN); IMAGE_FILE_HEADER myNtHeader; ReadFile(hFile,(LPVOID)myNtHeader,sizeof(IMAGE_FILE_HEADER),NumberOfBytesReadorWrite,NULL); IMAGE_SECTION_HEADER mySectionHeader; SetFilePointer(hFile,myDosHeader.e_lfanew sizeof(IMAGE_NT_HEADERS),NULL,FILE_BEGIN); ReadFile(hFile,(LPVOID)mySectionHeader,sizeof(IMAGE_SECTION_HEADER),NumberOfBytesReadorWrite,NULL); SetFilePointer(hFile,NULL,NULL,FILE_BEGIN); HGLOBAL hMem0; //读出节表的第一个文件位置以确PE头的大小 //申请同样大小的空间 hMemGlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,mySectionHeader.PointerToRawData); if(!hMem) { MessageBox(hDlg,TEXT(I cant get the Memory space!),TEXT(Error!!!),MB_OK | MB_ICONSTOP); return FALSE; } //将文件中的PE头部读取到申请的空间中 ReadFile(hFile,hMem,mySectionHeader.PointerToRawData,NumberOfBytesReadorWrite,NULL); CloseHandle(hFile); //上面是读/// //下面是写/// hFileCreateFile(Dump_Name,GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFileINVALID_HANDLE_VALUE) { MessageBox(hDlg,TEXT(I can open the dump file...),TEXT(Error!!),MB_OK | MB_ICONWARNING); return FALSE; } //下面是将空间中的数据写到dump文件的头部 WriteFile(hFile,hMem,mySectionHeader.PointerToRawData,NumberOfBytesReadorWrite,NULL); CloseHandle(hFile); GlobalFree(hMem); return TRUE;} 这里: 1. 获取当前进程列表使用的是CreateToolhelp32SnapshotProcess32First Process32Next 这三个函数即创建一个进程快照然后遍历它之前做ring3的进程注入的时候用的也是这个技术原理不是很难理解本质上就是一个链表的操作。 2. 在进程中确定进程的大小imagesize 使用的是从磁盘的文件PE头中读取SizeOfImage这个字段来获取。这里就有一个很有趣的知识点了我们先从原始的方法开始讲。 2.1 用ReadProcessMemory函数从从当前内存的进程映像工具PE格式的偏移获取到SizeOfImage的值的这种方法不太可靠要是加壳程序修改了映像中的PE头信息就要出错了。 2.2 LordPE使用的方法采用了对Module32Next来获取dump的进程的基本信息的。 BOOL WINAPI Module32First( HANDLE hSnapshot, //这是先前的CreateToolhelp32Snapshot函数返回的快照 LPMODULEENTRY32 lpme //这个是指向MODULEENTRY32结构的指针);下面是MUDULEENTRY32结构typedef struct tagMODULEENTRY32 { DWORD dwSize; DWORD th32ModuleID; DWORD th32ProcessID; DWORD GlblcntUsage; DWORD ProccntUsage; BYTE *modBaseAddr; DWORD modBaseSize; //这个是是我们要获取的关键 HMODULE hModule; TCHAR szModule[MAX_PATH]; TCHAR szExePath[MAX_PATH]; DWORD dwFlags;} MODULEENTRY32, *PMODULEENTRY32, *LPMODULEENTRY32; 这种方法会受到anti-dump技术的影响。 因为MUDULEENTRY32是从内核中PEB进程环境块获取的数据。 下面是PEB的结构。struct _PEB (sizeof488) 000 byte InheritedAddressSpace 001 byte ReadImageFileExecOptions 002 byte BeingDebugged 003 byte SpareBool 004 void *Mutant 008 void *ImageBaseAddress 00c struct _PEB_LDR_DATA *Ldr 010 struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters 014 void *SubSystemData 018 void *ProcessHeap 01c void *FastPebLock 020 void *FastPebLockRoutine 024 void *FastPebUnlockRoutine 028 uint32 EnvironmentUpdateCount 02c void *KernelCallbackTable 030 uint32 SystemReserved[2] 038 struct _PEB_FREE_BLOCK *FreeList 03c uint32 TlsExpansionCounter 040 void *TlsBitmap 044 uint32 TlsBitmapBits[2] 04c void *ReadOnlySharedMemoryBase 050 void *ReadOnlySharedMemoryHeap 054 void **ReadOnlyStaticServerData 058 void *AnsiCodePageData 05c void *OemCodePageData 060 void *UnicodeCaseTableData064 uint32 NumberOfProcessors 068 uint32 NtGlobalFlag 070 union _LARGE_INTEGER CriticalSectionTimeout 070 uint32 LowPart 074 int32 HighPart 070 struct __unnamed3 u 070 uint32 LowPart 074 int32 HighPart 070 int64 QuadPart 078 uint32 HeapSegmentReserve 07c uint32 HeapSegmentCommit 080 uint32 HeapDeCommitTotalFreeThreshold 084 uint32 HeapDeCommitFreeBlockThreshold 088 uint32 NumberOfHeaps 08c uint32 MaximumNumberOfHeaps 090 void **ProcessHeaps 094 void *GdiSharedHandleTable 098 void *ProcessStarterHelper 09c uint32 GdiDCAttributeList 0a0 void *LoaderLock 0a4 uint32 OSMajorVersion 0a8 uint32 OSMinorVersion 0ac uint16 OSBuildNumber 0ae uint16 OSCSDVersion 0b0 uint32 OSPlatformId 0b4 uint32 ImageSubsystem 0b8 uint32 ImageSubsystemMajorVersion 0bc uint32 ImageSubsystemMinorVersion 0c0 uint32 ImageProcessAffinityMask 0c4 uint32 GdiHandleBuffer[34] 14c function *PostProcessInitRoutine 150 void *TlsExpansionBitmap 154 uint32 TlsExpansionBitmapBits[32] 1d4 uint32 SessionId 1d8 void *AppCompatInfo 1dc struct _UNICODE_STRING CSDVersion 1dc uint16 Length 1de uint16 MaximumLength 1e0 uint16 *Buffer我们从FS[30]就可以获得这个PEB的首地址。然后在0C处的_PEB_LDR_DATA *Ldr是一个关键通过它我们能访问到typedef struct _PEB_LDR_DATA {ULONG Length;BOOLEAN Initialized;PVOID SsHandle;LIST_ENTRY InLoadOrderModuleList;LIST_ENTRY InMemoryOrderModuleList;LIST_ENTRY InInitializationOrderModuleList;} PEB_LDR_DATA, *PPEB_LDR_DATA;该结构的后三个成员是指向LDR_MODULE链表结构中相应三条双向链表头的指针分别是按照加载顺序、在内存中的地址顺序和初始化顺序排列的模块信息结构的指针。于是通过它我们能访问到_LDR_MODULE结构而这里面包括了本进程的SizeOfImage。_LDR_MODULE结构如下typedef struct _LDR_MODULE {LIST_ENTRY InLoadOrderModuleList;LIST_ENTRY InMemoryOrderModuleList;LIST_ENTRY InInitializationOrderModuleList;PVOID BaseAddress;PVOID EntryPoint;ULONG SizeOfImage; //进程的image sizeUNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;SHORT LoadCount;SHORT TlsIndex;LIST_ENTRY HashTableEntry;ULONG TimeDateStamp;} LDR_MODULE, *PLDR_MODULE; 所以我们得到关键的代码就是 //这里的几个代码是修改PEB的关键 __asm { mov eax,fs:[30h] //获得PEB地址 mov eax,[eax0ch] // 00c struct _PEB_LDR_DATA *Ldr mov eax,[eax0ch] // _LDR_MODULE的首地址 mov dword ptr [eax20h],1000h //eax20是保存image size的地方 } 上面的代码的作用就是把image size的大小改为了1000h这样我们用MODULEENTRY32得到的大小是不准确的。 2.3 针对上面的问题必须使用LordPE的corect image size 技术了它的原理很简单就是从磁盘PE文件头中读取真实的image size来修正获取到的数据从而避免了anti-dump的影响当然anti-dump技术还有很多不止这一种我也要慢慢去摸索。 3. 对齐节表问题 学过PE结构的朋友都指导FileAlignment磁盘对齐值和SectionAlignment内存对齐值是不一样的。 FileAlignment0x200h SectionAlignment:0x1000h 在PE加载器加载文件映像的时候就会在对齐值之间的差值中填0当然我们dump的时候连着这些0也一并dump下来了。这也就是为什么脱壳的程序普遍都比源程序大很多的原理当然实际情况不止这些IAT重建也会造成大小扩大。 另外还造成了一个问题就是 RA!RVA RS!RVS的问题 因为我们是从内从中直接dump出来的数据所以这时正常的情况应该是RARVA RSRVS这里可以手动修改或者编程实现即可原理上之前学PE的时候写的PEInfo差不多主要考察的PE结构的知识。 这是修改后的。 到这里dump就完成了还差IAT没修复。 可以采取手工的方法在文件中找一块空位逆向的重构IAT在修改PE头。 或者用ImportREC来自动修复。 修复完成后脱壳成功至此一个简单的脱壳工具就出来了。 这个学习笔记就当这段时间学习逆向脱壳的总结了留下了几个问题没解决 1. DLL脱壳后的重定位问题 2. VMP虚拟机壳寻找OEP问题。 留待以后解决了............. 信安的路果然还很长希望以后能继续多多学习思考总结分享向看雪上那些大神看齐。 下一阶段准备研究一些缓冲区溢出的内核的知识点继续看《0DAY》。离ISCC结束还有10天继续加油啦暑假一定要到北京ISCC决赛去。 -------------------------------分割线----------------------- 不知道怎么结尾就这样了吧 跑步去。转载于:https://www.cnblogs.com/LittleHann/p/3148349.html