逆向程序的时候,喜欢用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插件了
#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插件的使用方法:
如果是原版的OD,直接把编译好的DLL放到od主程序的目录就可以了,看雪版的OD把DLL放到plugin目录下。
附件中包含了CamelLu.idc,CamelLu Functions' Names Importer插件的源代码以及编译好的DLL
PS.
我这个插件还有点问题,就是调试DLL的话不能用,因为我发现调试DLL的时候_Plugingetvalue(VAL_MAINBASE)函数得到的是LoadDll.exe的基址,基址一错自然写名称的地方就错啦= =!
好了,明天还要干活,回去睡觉去了
[课程]Android-CTF解题方法汇总!