逆向程序的时候,喜欢用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!"); }


这个idc脚本文件没有main函数,因为我要使用快捷键来调用它

使用方法:

在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插件了

VS环境设置为  Use Multi-Byte Character Set

如果提示“Please set default char type to unsigned (option /J)”  解决方案如下:


  1. In Solution Explorer, open the shortcut menu for the project and then chooseProperties.
  2. In the project Property Pages dialog box, in the left pane underConfiguration Properties, expand C/C++ and then selectCommand Line.
  3. In the Additional Options pane, specify the/J compiler option.


需要注意的是 如果是用VS2012编译 在XP上OD启动加在这个插件会报错,找不到“msvcr110.dll” 但是XP上最多支持msvcr100.dll 即便找来了msvcr110.dll注册它 也是要出错的 所以如果需要在XP上的OD运行该插件 用VS2010编译该插件就行 VS2012编译只能在WIN7 WIN8的OD上运行

#include <windows.h> #include <Commdlg.h>	//for GetOpenFileName function. #include <tchar.h>		//for _tcscpy_s ... function. #include <stdlib.h>		//for _countof ... function. #include <Shlwapi.h>	//for String function of windows. #include <strsafe.h>	//for StringCchPrintf ... function.  #include "plugin.h"   #pragma comment(lib,"OLLYDBG.LIB")    static HWND hwnd = NULL;    BOOL APIENTRY DllMain( HMODULE hModule, 					  DWORD  ul_reason_for_call, 					  LPVOID lpReserved 					  ) { 	switch (ul_reason_for_call) 	{ 	case DLL_PROCESS_ATTACH:      	case DLL_THREAD_ATTACH: 	case DLL_THREAD_DETACH: 	case DLL_PROCESS_DETACH: 		break; 	} 	return TRUE; }  //下面四个函数全都是插件回调函数,只有前两个函数是编写OD插件必须有的!!!   //ODBG_PluginData这个函数是必须有的,作用就是设置插件的名字(在OD的Plugin)   extc int _export cdecl ODBG_Plugindata(TCHAR shortname[32])    {    	strcpy_s(shortname, 32, "IDA2OD");       	return PLUGIN_VERSION;   }   //ODBG_Plugininit这个函数也是必须有的,看名字就知道是用来做一些初始化工作啦   //ollydbgversion参数可以用来检查当前OD的版本,确保插件运行在兼容的OD版本上,hw是OD主窗口的句柄   extc int _export cdecl ODBG_Plugininit(int ollydbgversion, HWND hw, DWORD *features)    {   	if (ollydbgversion < PLUGIN_VERSION)   	{   		MessageBox(hw, TEXT("CamelLu is not compatible with your Ollydbg version!"), 0, 0);   		return -1;   	}   	hwnd = hw;   	return 0;   }    //ODBG_Pluginmenu这个函数是用来添加菜单的,每个菜单项之间用'|'字符隔开   extc int _export cdecl ODBG_Pluginmenu(int origin, TCHAR data[4096], VOID *item)    {   	if (origin == PM_MAIN)   	{ 		strcpy_s(data, 4096, "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;        	TCHAR wszFile[MAX_PATH];    	PTSTR pBuffer = NULL;   	PTSTR pLocate = NULL;   	PTSTR pDellimiter = NULL;   	PTSTR pTemp = NULL;   	DWORD dwFileSize = 0;   	DWORD dwBytesRead = 0;   	DWORD dwImageBase = 0;   	DWORD dwAddr = 0;    	int	nSize; 	t_table *table = NULL;   	t_sorted *sorted = NULL;   	t_module *module = NULL;   	HANDLE hFile = INVALID_HANDLE_VALUE;   	int nIndex = 0;   	if (origin == PM_MAIN)   		if (action == 0)   		{    			ZeroMemory(&ofn, sizeof(ofn));   			ofn.lStructSize = sizeof(ofn);   			ofn.hwndOwner = hwnd;   			ofn.lpstrFile = wszFile;   			ofn.lpstrFile[0] = '\0';   			ofn.nMaxFile = _countof(wszFile);   			ofn.lpstrFilter = TEXT(".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())   				{   					MessageBox(hwnd, TEXT("No debugee now!!!"), 0, 0);   					return;   				}   				hFile = CreateFile(   					wszFile,   					GENERIC_READ,   					FILE_SHARE_READ,   					NULL,   					OPEN_EXISTING,   					FILE_ATTRIBUTE_NORMAL,   					NULL);   				if (INVALID_HANDLE_VALUE == hFile)   				{   					MessageBox(hwnd, TEXT("Failed to open .lu file!"), 0, 0);   					return;   				}   				dwFileSize = GetFileSize(hFile,NULL);   				if (INVALID_FILE_SIZE == dwFileSize)   				{   					MessageBox(hwnd, TEXT("GetFileSize failed!"), 0, 0);   					CloseHandle(hFile);   					return;   				}   				pBuffer = (PTSTR)VirtualAlloc(   					NULL,   					dwFileSize + sizeof(TCHAR),   					MEM_COMMIT,   					PAGE_READWRITE   					);   				if (NULL == pBuffer)   				{   					MessageBox(hwnd, TEXT("VirtualAlloc failed!"), 0, 0);   					CloseHandle(hFile);   					return;   				}   				if (!ReadFile(   					hFile,   					pBuffer,   					dwFileSize,   					&dwBytesRead,   					NULL)   					)   				{   					MessageBox(hwnd, TEXT("ReadFile failed!"), 0, 0);   					VirtualFree(pBuffer, 0, MEM_RELEASE);   					CloseHandle(hFile);   					return;   				}   				CloseHandle(hFile);   				table = (t_table*)_Plugingetvalue(VAL_MODULES);   				if (NULL == table)   				{   					MessageBox(hwnd, TEXT("Get modules failed!"), 0, 0);   					VirtualFree(pBuffer, 0, MEM_RELEASE);   					CloseHandle(hFile);   					return;   				}   				sorted = &table->data;   				for (nIndex = 0;nIndex < sorted->n;++nIndex)   				{   					module = (t_module *)((DWORD)sorted->data + nIndex * sorted->itemsize);   					if (0 == strcmp(module->path, (char *)_Plugingetvalue(VAL_EXEFILENAME)))   					{   						dwImageBase = module->base;   						break;   					}   				}   				pLocate = pBuffer;   				pDellimiter = strstr(pLocate, "\r\n");   				while (*(pDellimiter + 2) != 0)   				{   					nSize = pDellimiter - pLocate +  sizeof(TCHAR); 					pTemp = (PTSTR)VirtualAlloc(NULL, nSize, MEM_COMMIT,PAGE_READWRITE);   					if (NULL == pTemp)   					{   						MessageBox(hwnd, TEXT("VirtualAlloc in loop failed!"), 0, 0);   						VirtualFree(pBuffer, 0, MEM_RELEASE);   						return;   					}    					strncpy_s(pTemp, nSize, pLocate, pDellimiter - pLocate);                       sscanf_s(pTemp,"%X-",&dwAddr);   					 					_Quickinsertname(dwImageBase + dwAddr, NM_LABEL, strchr(pTemp,'-') + sizeof(TCHAR));  					VirtualFree(pTemp, 0, MEM_RELEASE);   					pLocate = pDellimiter + 2;   					pDellimiter = strstr (pLocate, "\r\n");   				}   				_Mergequicknames();   				VirtualFree(pBuffer,0,MEM_RELEASE);   				MessageBox(hwnd, TEXT("I am done^ ^"), TEXT("CamelLu"), MB_OK);   			}    		}   		else if (action == 1)   		{   			MessageBox(hwnd, TEXT("CamelLu Functions\' Names Importer\r\nWritten by CamelLu 2011.7.19\r\n"), TEXT("Camellu"), MB_ICONINFORMATION);   		}    }

OD插件的使用方法:

如果是原版的OD,直接把编译好的DLL放到od主程序的目录就可以了,看雪版的OD把DLL放到plugin目录下。

https://blog.51cto.com/whatday/1382484