逆向程序的时候,喜欢用IDA静态分析,用OD动态调试,如果把IDA分析出来的函数名称都导入到OD中,调试的时候就知道哪些函数不需要再看了。以前我一直用GODUP的map loader,但是有些时候感觉它有点问题,还有一个插件叫MapConv也有这个功能,不过我还是打算自己写一个,主要是为了学习如何编写OD插件
首先我用一个IDC脚本将idb中所有函数的名称都导出到一个文件当中
代码:
//CamelLu.idc #include <idc.idc> static CamelLu() { auto addr,path,file,imagebase; Message("Functions' Names Dumper - CamelLu(2011.7.19)\n"); file = fopen(GetInputFilePath(),"rb"); if (0 == file) { Warning("open INPUTFILE failed!"); return; } if (0 != fseek(file,0x3c,0)) { Warning("seek e_lfanew failed!"); fclose(file); return; } imagebase = readlong(file,0); if (0 != fseek(file,imagebase + 0x34,0)) { Warning("seek imagebase failed!"); fclose(file); return; } imagebase = readlong(file,0); fclose(file); path = AskFile(1,"*.lu","Please enter output file name"); if (BADADDR == path) { Warning("AskFile failed!"); return; } file = fopen(path,"w"); if (0 == file) { Warning("fopen failed!"); return; } addr = MinEA(); if ("" != GetFunctionName(addr)) fprintf(file,"%X---%s\n",addr,GetFunctionName(addr)); for(addr = NextFunction(addr);BADADDR != addr;addr = NextFunction(addr)) fprintf(file,"%X-%s\n",addr - imagebase,GetFunctionName(addr)); fclose(file); Message("output functions' names finished!"); }
使用方法:
在IDA的安装目录下面找到idc这个目录,把上面这个脚本保存到这个目录中,然后idc目录下找到
ida.idc这个文件,打开它,在#include<idc.idc>的下面加入#include<CamelLu.idc>,然后在它的main函数里面加入AddHotkey("Alt-9","CamelLu");
接下来你就可以在IDA中按Alt+9来调用这个脚本了(为脚本选择热键的时候要注意,如果这个热键已经被其他脚本或者插件使用的话,AddHotKey会失败,IDA不会给你提示的噢)
接下来再写一个OD插件来解析上面输出的文件,用Quickinsertname和Mergequicknames函数把函数名加到相应的地址就OK。我对插件框架的几个函数用途都写了简单的注释,相信大家看过之后都能自己写OD插件了
代码:
#include <windows.h> #include <string.h> #include "plugin.h" #pragma comment(lib,"OLLYDBG.LIB") static HINSTANCE hinst = NULL; static HWND hwnd = NULL; BOOL WINAPI DllEntryPoint(HINSTANCE hinstance,DWORD dwreason,LPVOID lpvreserved) { if (dwreason==DLL_PROCESS_ATTACH) hinst=hinstance; return 1; } //下面四个函数全都是插件回调函数,只有前两个函数是编写OD插件必须有的!!! //ODBG_PluginData这个函数是必须有的,作用就是设置插件的名字(在OD的Plugin) extc int _export cdecl ODBG_Plugindata(char shortname[32]) { strcpy(shortname,"CamelLu"); return PLUGIN_VERSION; } //ODBG_Plugininit这个函数也是必须有的,看名字就知道是用来做一些初始化工作啦 //ollydbgversion参数可以用来检查当前OD的版本,确保插件运行在兼容的OD版本上,hw是OD主窗口的句柄 extc int _export cdecl ODBG_Plugininit(int ollydbgversion,HWND hw,ulong *features) { hwnd = hw; return 0; } //ODBG_Pluginmenu这个函数是用来添加菜单的,每个菜单项之间用'|'字符隔开 extc int _export cdecl ODBG_Pluginmenu(int origin,char data[4096],void *item) { if (origin == PM_MAIN) strcpy(data,"0&Load functions\' names|1&About"); return 1; } //ODBG_Pluginaction函数用于添加响应ODBG_Pluginmenu函数添加的菜单,很简单,看看下面的代码就明白了 extc void _export cdecl ODBG_Pluginaction(int origin,int action,void *item) { OPENFILENAME ofn; wchar_t wszFile[MAX_PATH]; unsigned char *pBuffer = NULL; unsigned char *pLocate = NULL; unsigned char *pDellimiter = NULL; unsigned char *pTemp = NULL; DWORD dwFileSize = 0; DWORD dwBytesRead = 0; DWORD dwImageBase = 0; DWORD dwAddr = 0; char szBuffer[10]; HANDLE hFile = INVALID_HANDLE_VALUE; if (origin == PM_MAIN) if (action == 0) { ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwnd; ofn.lpstrFile = wszFile; ofn.lpstrFile[0] = L'\0'; ofn.nMaxFile = sizeof(wszFile); ofn.lpstrFilter = L".lu\0*.lu\0"; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; if (GetOpenFileName(&ofn)==TRUE) { if (STAT_NONE == _Getstatus()) { MessageBoxW(hwnd,L"No debugee now!!!",0,0); return; } hFile = CreateFileW( wszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { MessageBoxW(hwnd,L"Failed to open .lu file!",0,0); return; } dwFileSize = GetFileSize(hFile,NULL); if (INVALID_FILE_SIZE == dwFileSize) { MessageBoxW(hwnd,L"GetFileSize failed!",0,0); CloseHandle(hFile); return; } pBuffer = VirtualAlloc( NULL, dwFileSize + 1 * sizeof(unsigned char), MEM_COMMIT, PAGE_READWRITE ); if (NULL == pBuffer) { MessageBoxW(hwnd,L"VirtualAlloc failed!",0,0); CloseHandle(hFile); return; } if (!ReadFile( hFile, pBuffer, dwFileSize, &dwBytesRead, NULL) ) { MessageBoxW(hwnd,L"ReadFile failed!",0,0); VirtualFree(pBuffer,0,MEM_RELEASE); CloseHandle(hFile); return; } CloseHandle(hFile); dwImageBase = _Plugingetvalue(VAL_MAINBASE); pLocate = pBuffer; pDellimiter = strstr(pLocate,"\r\n"); while (*(pDellimiter + 2) != 0) { pTemp = VirtualAlloc(NULL,pDellimiter - pLocate + 1 * sizeof(unsigned char),MEM_COMMIT,PAGE_READWRITE); if (NULL == pTemp) { MessageBoxW(hwnd,L"VirtualAlloc in loop failed!",0,0); VirtualFree(pBuffer,0,MEM_RELEASE); return; } strncpy(pTemp,pLocate,pDellimiter - pLocate); sscanf(pTemp,"%X-",&dwAddr); _Quickinsertname(dwImageBase + dwAddr,NM_LABEL,strchr(pTemp,'-') + 1 * sizeof(unsigned char)); VirtualFree(pTemp,0,MEM_RELEASE); pLocate = pDellimiter + 2; pDellimiter = strstr(pLocate,"\r\n"); } _Mergequicknames(); VirtualFree(pBuffer,0,MEM_RELEASE); MessageBoxW(hwnd,L"I am done^ ^",L"CamelLu",MB_OK); } } else if (action == 1) { MessageBoxW(hwnd,L"CamelLu Functions\' Names Importer\r\nWritten by CamelLu 2011.7.19\r\n",L"Camellu",MB_ICONINFORMATION); } }
如果是原版的OD,直接把编译好的DLL放到od主程序的目录就可以了,看雪版的OD把DLL放到plugin目录下。
附件中包含了CamelLu.idc,CamelLu Functions' Names Importer插件的源代码以及编译好的DLL
PS.
我这个插件还有点问题,就是调试DLL的话不能用,因为我发现调试DLL的时候_Plugingetvalue(VAL_MAINBASE)函数得到的是LoadDll.exe的基址,基址一错自然写名称的地方就错啦= =!
好了,明天还要干活,回去睡觉去了