call dword ptr ds:[<&KERNEL32.GetVersion>]
即表示这条指令是在调用kernel32.dll中的GetVersion函数,其实FF1578604000 更加贴近硬件的翻译是
call dword ptr [00406078]
将00406079这个地址中的数据按双字解释,发现这个地址上存放的是77E6C07F,也就是说上面的call指令实际上相当于
call 77E6C07F
不错77E6C07F这个地址就是xdos.exe进程空间中kernel32.dll中GetVersion函数的起址。好像有点深度哦,知道研究下。
下面是通过内存中已经加载模块的分析过程,当然静态的也可以把这些信息分析出来,不过静态的PE文件就得不到77E6C07F这个入口地址,但是函数名这些还是可以获得的。
以下程序可以对任何可见的进程的可见模块进行分析(是可见的,目前本人水平垃圾,还没有能力发现一些“别具用心”的模块)。
1.系统进程枚举程序
// 进程信息描述结构体
typedef struct tagOneProcessInfo
{
DWORD dwProcessID; //进程ID
DWORD dwParentProcessID; //父进程ID
DWORD dwThreadsNo; //拥有线程数量
std::string strProcessName; //进程名
tagOneProcessInfo()
{
dwProcessID = -1;
dwParentProcessID = -1;
dwThreadsNo = -1;
strProcessName.assign("");
}
}OneProcessInfo, *POneProcessInfo;
// 功 能: 枚举系统进程
// 输入参数: 一个map<DWORD, OneProcessInfo>,用于保存系统的进程信息
// 返回结果: 成功返回TRUE,否则FALSE
// 说 明: map的第一个字段是就进程ID,第二个字段是该进程的详细信息
BOOL GetProcessesInfo(map<DWORD, OneProcessInfo> &mapProInfo)
{
HANDLE handle = NULL;
PROCESSENTRY32 proInfo;
handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if(INVALID_HANDLE_VALUE == handle)
{
return FALSE;
}
ZeroMemory(&proInfo, sizeof(proInfo));
proInfo.dwSize = sizeof(proInfo);
// 枚举系统的进程
mapProInfo.clear();
for(BOOL bHas = Process32First(handle, &proInfo); bHas == TRUE ; bHas = Process32Next(handle, &proInfo))
{
OneProcessInfo oneProcessInfo;
oneProcessInfo.dwProcessID = proInfo.th32ProcessID;
oneProcessInfo.dwParentProcessID = proInfo.th32ParentProcessID;
oneProcessInfo.dwThreadsNo = proInfo.cntThreads;
oneProcessInfo.strProcessName.assign(proInfo.szExeFile);
mapProInfo.insert(pair<DWORD, OneProcessInfo>(proInfo.th32ProcessID, oneProcessInfo));
}
// 关闭句柄
CloseHandle(handle);
return TRUE;
}
2.某个特定进程的模块枚举程序
// 进程模块信息描述结构体
typedef struct tagOneProcessModulesInfo
{
DWORD dwProcessID; //模块所在进程ID
DWORD dwModuleID; //模块ID
DWORD dwGlobleUsage; //该模块当前被系统引用的次数
unsigned char * ucpBaseAddress; //模块在内存中的基地址
DWORD dwModuleSize; //模块的大小
std::string strModuleName; //模块名
std::string strModulePath; //模块路径
tagOneProcessModulesInfo()
{
dwProcessID = -1;
dwModuleID = -1;
dwGlobleUsage = -1;
ucpBaseAddress = NULL;
dwModuleSize = 0;
strModuleName.assign("");
strModulePath.assign("");
}
}OneProcessModulesInfo, *POneProcessModulesInfo;
// 功 能: 枚举进程的模块信息
// 输入参数: 第一个是进程ID;第二个是map<DWORD, OneProcessModulesInfo>,用于保存进程的模块信息
// 返回结果: 成功返回TRUE,否则FALSE
// 说 明: map的第一个字段是就模块ID,第二个字段是该模块的详细信息
BOOL GetProcessModules(DWORD dwProcessID, map<DWORD, OneProcessModulesInfo> &mapModuleInfo)
{
if(dwProcessID < 0)
{
return FALSE;
}
HANDLE handle = NULL;
MODULEENTRY32 modInfo;
handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessID);
if(INVALID_HANDLE_VALUE == handle)
{
return FALSE;
}
ZeroMemory(&modInfo, sizeof(modInfo));
modInfo.dwSize = sizeof(modInfo);
// 枚举进程的模块
mapModuleInfo.clear();
for(BOOL bHas = Module32First(handle, &modInfo); bHas == TRUE; bHas = Module32Next(handle, &modInfo))
{
OneProcessModulesInfo oneModuleInfo;
oneModuleInfo.dwProcessID = dwProcessID;
oneModuleInfo.dwModuleID = modInfo.th32ModuleID;
oneModuleInfo.dwGlobleUsage = modInfo.GlblcntUsage;
oneModuleInfo.ucpBaseAddress = modInfo.modBaseAddr;
oneModuleInfo.dwModuleSize = modInfo.modBaseSize;
oneModuleInfo.strModuleName = modInfo.szModule;
oneModuleInfo.strModulePath = modInfo.szExePath;
mapModuleInfo.insert(pair<DWORD, OneProcessModulesInfo>(modInfo.th32ModuleID, oneModuleInfo));
}
// 关闭句柄
CloseHandle(handle);
return TRUE;
}
3.IAT表分析,API信息分析程序
这段代码的数据结构没有组织好,对于通过入口地址来查询API信息,效率是地下的。
// 模块调用的API信息结构体
typedef struct tagAPIInfo
{
DWORD dwAPIAddress; //API真实地址在该模块的保存地址
std::string strDllNameOfAPI; //导入这个API的Dll文件
std::string strAPIName; //API名字(可能是空)
DWORD dwAPIID; //导入API的序号
tagAPIInfo()
{
dwAPIAddress = -1;
strDllNameOfAPI.assign("");
strAPIName.assign("");
dwAPIID = -1;
}
}APIInfo, *PAPIInfo;
// 功 能: 分析给定进程中给定模块的PE导入表和调用API信息
// 输入参数: 第一个是进程ID;第二个是OneProcessModulesInfo,传递模块信息,第三个参数是返回API信息的
// 返回结果: 成功返回TRUE,否则FALSE
// 说 明: 第三个参数的第一个字段是Dll文件名,第二个字段是其导出函数具体信息
BOOL ModulePEIATAnalyse(DWORD dwProcessID, OneProcessModulesInfo moduleInfo, map<string, vector<APIInfo> > &mapAPIInfo)
{
if(dwProcessID < 0)
{
return FALSE;
}
mapAPIInfo.clear();
vector<APIInfo> vecAPIInfo;
//打开给定的进程对象
HANDLE proHandle = OpenProcess(PROCESS_VM_READ, FALSE, dwProcessID);
if(proHandle == NULL)
{
return FALSE;
}
HGLOBAL mem = GlobalAlloc(GPTR, moduleInfo.dwModuleSize);
if(mem == NULL)
{
CloseHandle(proHandle);
return FALSE;
}
LPTSTR pMem = (LPTSTR)GlobalLock(mem);
if(0 != ReadProcessMemory(proHandle, moduleInfo.ucpBaseAddress, pMem, moduleInfo.dwModuleSize, NULL))
{
//判断模块是不是PE模块
IMAGE_DOS_HEADER *pDosHeader = (IMAGE_DOS_HEADER *)pMem;
if(pDosHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS *pNTHeader = (IMAGE_NT_HEADERS *)(pMem + pDosHeader->e_lfanew);
if(pNTHeader->Signature == IMAGE_NT_SIGNATURE)
{
//是PE模块
//获得导入表的地址
long pIATRVA = pNTHeader->OptionalHeader.DataDirectory[sizeof(IMAGE_DATA_DIRECTORY)].VirtualAddress;
if(pIATRVA != NULL)
{
//存在导入表
//获得实际上导入表在内存中的位置
LPTSTR pIATAddress = pIATRVA + pMem;
IMAGE_IMPORT_DESCRIPTOR *pImportDescriptor = (IMAGE_IMPORT_DESCRIPTOR *)pIATAddress;
for(; ; pImportDescriptor++)
{
//判断导入描述符是否结束
if(pImportDescriptor->OriginalFirstThunk == 0 && pImportDescriptor->TimeDateStamp == 0 /
&& pImportDescriptor->ForwarderChain == 0 && pImportDescriptor->Name == 0 && /
pImportDescriptor->FirstThunk == 0)
{
break;
}
vecAPIInfo.clear();
//获得DLL文件的名称
long lDllName = pImportDescriptor->Name;
LPTSTR lpDllName = pMem + lDllName;
string strDllName(lpDllName);
strDllName.substr(0, strDllName.length() - 4);
long lThunkData = pImportDescriptor->OriginalFirstThunk;
if(lThunkData == 0)
{
//lThunkData = pImportDescriptor->FirstThunk;
// 释放内存 关闭句柄
GlobalUnlock(mem);
GlobalFree(mem);
CloseHandle(proHandle);
return FALSE;
}
IMAGE_THUNK_DATA * lpThunkData = (IMAGE_THUNK_DATA *)(pMem + lThunkData);
//导入的函数
int nFirstThunkOffset = 0;
for(long lImageThunkData = lpThunkData->u1.Ordinal; lImageThunkData != 0; lImageThunkData = (++lpThunkData)->u1.Ordinal)
{
APIInfo apiInfo;
apiInfo.strDllNameOfAPI = strDllName;
long lSecrialFuncion = -1;
unsigned char * cpFunName = NULL;
if(lImageThunkData & IMAGE_ORDINAL_FLAG32)
{
//该函数是以序号导入的
lSecrialFuncion = lImageThunkData & 0x7fffffff;
}
else
{
//该函数是以函数名导入的
IMAGE_IMPORT_BY_NAME importByName = *(IMAGE_IMPORT_BY_NAME*)(pMem + lImageThunkData);
lSecrialFuncion = importByName.Hint;
cpFunName = &importByName.Name[0];
}
apiInfo.dwAPIAddress = (long)moduleInfo.ucpBaseAddress + pImportDescriptor->FirstThunk + nFirstThunkOffset;
apiInfo.dwAPIID = lSecrialFuncion;
apiInfo.strAPIName.assign((char *)cpFunName);
vecAPIInfo.push_back(apiInfo);
nFirstThunkOffset += 4;
}
mapAPIInfo.insert(pair<string, vector<APIInfo> >(strDllName, vecAPIInfo));
}
}
}
}
}
// 释放内存 关闭句柄
GlobalUnlock(mem);
GlobalFree(mem);
CloseHandle(proHandle);
return TRUE;
}
Trackback: http://tb.blog.youkuaiyun.com/TrackBack.aspx?PostId=740114