// ViewDlg.cpp : 实现文件 // #include "stdafx.h" #include "HandleMemory.h" #include "ViewDlg.h" #include "afxdialogex.h" // CViewDlg 对话框 IMPLEMENT_DYNAMIC(CViewDlg, CDialogEx) CViewDlg::CViewDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CViewDlg::IDD, pParent) , m_strProcess(_T("")) , m_strDllName(_T("")) , m_strFunc(_T("")) { m_dwID = 0; } CViewDlg::~CViewDlg() { } void CViewDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Text(pDX, IDC_EDIT_PROCESS, m_strProcess); DDX_Control(pDX, IDC_LIST_MEMORY_VIEW, m_ViewList); DDX_Text(pDX, IDC_EDIT_DLL_NAME, m_strDllName); DDX_Text(pDX, IDC_EDIT_FUNCTION, m_strFunc); } BEGIN_MESSAGE_MAP(CViewDlg, CDialogEx) ON_BN_CLICKED(IDC_BUTTON_PROCESS, &CViewDlg::OnBnClickedButtonProcess) ON_BN_CLICKED(IDC_BUTTON_GET_API, &CViewDlg::OnBnClickedButtonGetApi) END_MESSAGE_MAP() // CViewDlg 消息处理程序 void CViewDlg::OnBnClickedButtonProcess() { // TODO: 在此添加控件通知处理程序代码 CChooseProcessDlg dlg; DWORD dwID = 0; char szProcessName[MAX_PATH] = {0}; if(IDOK == dlg.DoModal()) { dwID = dlg.GetProcessID(); ::lstrcat(szProcessName, dlg.GetProcessName()); m_strProcess.Format("pid:%d exe file:%s", dwID, szProcessName); UpdateData(FALSE); m_dwID = dwID; // 获取内存的详情信息 GetMemoryInfo(dwID); } } BOOL CViewDlg::GetMemoryInfo(DWORD dwID) { HMODULE hBaseAddress = NULL; char szDllNameArray[MAX_PATH][MAX_PATH] = {0}; DWORD dwDllNum = 0; DWORD64 dwAddressArray[MAX_PATH] = {0}; DWORD dwIndex = 0; BOOL b32 = FALSE; // 打开进程 HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwID); if(NULL == hProcess) { char szErr[MAX_PATH] = {0}; ::wsprintf(szErr, "Open Process Error!\nError Code:%d\n", ::GetLastError()); ::MessageBox(m_hWnd, szErr, "Error", MB_OK | MB_ICONWARNING); return FALSE; } // 判断是32位还是64位 ::IsWow64Process(hProcess, &b32); // 获取进程的基址 GetProcessBaseAddress(&hBaseAddress, hProcess); // 从导入表中获取加载的DLL模块名称 GetProcessDllName(hProcess, hBaseAddress, szDllNameArray, dwDllNum, b32); // 根据导入表和导入表中的函数地址,暴力遍历出加载的DLL的模块基址 for(dwIndex = 0; dwIndex < dwDllNum; dwIndex++) { dwAddressArray[dwIndex] = GetProcessDllBaseAddress(hProcess, hBaseAddress, szDllNameArray[dwIndex], b32); } // 显示 // 清空列表框内容 m_ViewList.ResetContent(); char szTemp[MAX_PATH] = {0}; ::wsprintf(szTemp, "Process PID:%d", dwID); m_ViewList.AddString(szTemp); if(b32) { ::wsprintf(szTemp, "32bits"); } else { ::wsprintf(szTemp, "64bits"); } m_ViewList.AddString(szTemp); m_ViewList.AddString(""); ::wsprintf(szTemp, "Base Address:\n0x%016I64x", (DWORD64)hBaseAddress); m_ViewList.AddString(szTemp); m_ViewList.AddString(""); for(dwIndex = 0; dwIndex < dwDllNum; dwIndex++) { ::wsprintf(szTemp, "Dll Name:%s", szDllNameArray[dwIndex]); m_ViewList.AddString(szTemp); ::wsprintf(szTemp, "Load Base Address:0x%016I64x", dwAddressArray[dwIndex]); m_ViewList.AddString(szTemp); m_ViewList.AddString(""); } return TRUE; } BOOL CViewDlg::GetProcessBaseAddress(HMODULE *lpBaseAddress, HANDLE hProcess) { ::EnumProcessModules(hProcess, lpBaseAddress, sizeof(HMODULE), NULL); return TRUE; } BOOL CViewDlg::GetProcessDllName(HANDLE hProcess, HMODULE hBaseAddress, char szDllNameArray[MAX_PATH][MAX_PATH], DWORD &dwDllNum, BOOL b32) { DWORD64 dwBaseAddress = (DWORD64)hBaseAddress; WORD MZ = 0; DWORD dwlfanew = 0; DWORD PE00 = 0; DWORD64 dwTemp = 0; // 判断PE结构 ::ReadProcessMemory(hProcess, (LPCVOID)dwBaseAddress, &MZ, 2, &dwTemp); if(2 != dwTemp) { char szErr[MAX_PATH] = {0}; ::wsprintf(szErr, "Read Process Memory Error!\nError Code:%d", ::GetLastError()); ::MessageBox(m_hWnd, szErr, NULL, MB_OK | MB_ICONWARNING); return FALSE; } if(MZ != IMAGE_DOS_SIGNATURE) { return FALSE; } ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + 0x003c), &dwlfanew, 4, &dwTemp); ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwlfanew), &PE00, 4, &dwTemp); if(4 != dwTemp) { char szErr[MAX_PATH] = {0}; ::wsprintf(szErr, "Read Process Memory Error!\nError Code:%d", ::GetLastError()); ::MessageBox(m_hWnd, szErr, NULL, MB_OK | MB_ICONWARNING); return FALSE; } if(PE00 != IMAGE_NT_SIGNATURE) { return FALSE; } // 根据32位和64位的区别,分别读取内存 // 32位 if(b32) { // 从PE头文件目录获取导入表 // 获取导入表的起始偏移和大小 DWORD dwIATRVA = 0; DWORD dwIATSize = 0; ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwlfanew + 4 + 20 + 96 + 8), &dwIATRVA, 4, NULL); ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwlfanew + 4 + 20 + 96 + 8 + 4), &dwIATSize, 4, NULL); // 遍历DLL全称 DWORD dwIndex = (dwIATSize - 1)/20; dwDllNum = dwIndex; DWORD dwOffsetDllName = 0; char szTemp[50] = {0}; for(DWORD i = 0; i < dwIndex; i++) { // 获取DLL名称的偏移 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwIATRVA + i*20 + 12), &dwOffsetDllName, 4, NULL); // 获取DLL名称的地址并读取 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwOffsetDllName), szTemp, 50, NULL); ::lstrcpy(szDllNameArray[i], szTemp); } } // 64位 else { // 从PE头文件目录获取导入表 // 获取导入表的起始偏移和大小 DWORD dwIATRVA = 0; DWORD dwIATSize = 0; ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwlfanew + 4 + 20 + 112 + 8), &dwIATRVA, 4, NULL); ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwlfanew + 4 + 20 + 112 + 8 + 4), &dwIATSize, 4, NULL); // 遍历DLL全称 DWORD dwIndex = (dwIATSize - 1)/20; dwDllNum = dwIndex; DWORD dwOffsetDllName = 0; char szTemp[50] = {0}; for(DWORD i = 0; i < dwIndex; i++) { // 获取DLL名称的偏移 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwIATRVA + i*20 + 12), &dwOffsetDllName, 4, NULL); // 获取DLL名称的地址并读取 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwOffsetDllName), szTemp, 50, NULL); ::lstrcpy(szDllNameArray[i], szTemp); } } return TRUE; } DWORD64 CViewDlg::GetProcessDllBaseAddress(HANDLE hProcess, HMODULE hBaseAddress, char szDllName[MAX_PATH], BOOL b32) { DWORD64 dwBaseAddress = (DWORD64)hBaseAddress; DWORD dwlfanew = 0; ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + 0x003c), &dwlfanew, 4, NULL); // 根据32位和64位的区别,分别读取内存 // 32位 if(b32) { // 从PE头文件目录获取导入表 // 获取导入表的起始偏移和大小 DWORD dwIATRVA = 0; DWORD dwIATSize = 0; ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwlfanew + 4 + 20 + 96 + 8), &dwIATRVA, 4, NULL); ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwlfanew + 4 + 20 + 96 + 8 + 4), &dwIATSize, 4, NULL); // 遍历DLL全称 DWORD dwIndex = (dwIATSize - 1)/20; DWORD dwOffsetDllName = 0; DWORD dwDllNameLen = ::lstrlen(szDllName) + 1; char szTemp[MAX_PATH] = {0}; for(DWORD i = 0; i < dwIndex; i++) { // 获取DLL名称的偏移 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwIATRVA + i*20 + 12), &dwOffsetDllName, 4, NULL); // 获取DLL名称的地址并读取 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwOffsetDllName), szTemp, dwDllNameLen, NULL); if(0 == ::lstrcmpi(szDllName, szTemp)) // 不区分大小写 { DWORD dwFunctionAddress = 0; // 读取DLL中的函数地址 // 获取DLL中的函数的偏移地址 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwIATRVA + i*20 + 16), &dwFunctionAddress, 4, NULL); // 读取DLL中的函数的地址 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwFunctionAddress), &dwFunctionAddress, 4, NULL); // 根据DLL中的函数地址暴力搜索出DLL的加载基址 // 原理是:文件是对齐64k(0x10000)装载进内存的,DLL是一个PE结构文件 DWORD64 dwRet = GetDllBase(hProcess, dwFunctionAddress, b32); return dwRet; } } } // 64位 else { // 从PE头文件目录获取导入表 // 获取导入表的起始偏移和大小 DWORD dwIATRVA = 0; DWORD dwIATSize = 0; ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwlfanew + 4 + 20 + 112 + 8), &dwIATRVA, 4, NULL); ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwlfanew + 4 + 20 + 112 + 8 + 4), &dwIATSize, 4, NULL); // 遍历DLL全称 DWORD dwIndex = (dwIATSize - 1)/20; DWORD dwOffsetDllName = 0; DWORD dwDllNameLen = ::lstrlen(szDllName) + 1; char szTemp[MAX_PATH] = {0}; for(DWORD i = 0; i < dwIndex; i++) { // 获取DLL名称的偏移 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwIATRVA + i*20 + 12), &dwOffsetDllName, 4, NULL); // 获取DLL名称的地址并读取 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwOffsetDllName), szTemp, dwDllNameLen, NULL); if(0 == ::lstrcmpi(szDllName, szTemp)) // 不区分大小写 { DWORD64 dwFunctionAddress = 0; // 读取DLL中的函数地址 // 获取DLL中的函数的偏移地址 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwIATRVA + i*20 + 16), &dwFunctionAddress, 4, NULL); // 读取DLL中的函数的地址 ::ReadProcessMemory(hProcess, (LPCVOID)(dwBaseAddress + dwFunctionAddress), &dwFunctionAddress, 8, NULL); // 根据DLL中的函数地址暴力搜索出DLL的加载基址 // 原理是:文件是对齐64k(0x10000)装载进内存的,DLL是一个PE结构文件 DWORD64 dwRet = GetDllBase(hProcess, dwFunctionAddress, b32); return dwRet; } } } return 0; } DWORD64 CViewDlg::GetDllBase(HANDLE hProcess, DWORD64 dwFunctionAddress, BOOL b32) { WORD MZ = 0; DWORD dwlfanew = 0; DWORD PE00 = 0; if(b32) { dwFunctionAddress = dwFunctionAddress & 0xFFFF0000; } else { dwFunctionAddress = dwFunctionAddress & 0xFFFFFFFFFFFF0000; } do { ::ReadProcessMemory(hProcess, (LPCVOID)dwFunctionAddress, &MZ, 2, NULL); if(IMAGE_DOS_SIGNATURE == MZ) { ::ReadProcessMemory(hProcess, (LPCVOID)(dwFunctionAddress + 0x003c), &dwlfanew, 4, NULL); ::ReadProcessMemory(hProcess, (LPCVOID)(dwFunctionAddress + dwlfanew), &PE00, 4, NULL); if(IMAGE_NT_SIGNATURE == PE00) { return dwFunctionAddress; } } dwFunctionAddress = dwFunctionAddress - 0x10000; }while(dwFunctionAddress >= 0x10000000); return 0; } void CViewDlg::OnBnClickedButtonGetApi() { // TODO: 在此添加控件通知处理程序代码 UpdateData(TRUE); char szDllName[MAX_PATH] = {0}; char szFuncName[MAX_PATH] = {0}; ::lstrcpy(szDllName, m_strDllName.GetBuffer(0)); ::lstrcpy(szFuncName, m_strFunc.GetBuffer(0)); HMODULE hBaseAddress = NULL; BOOL b32 = FALSE; // 打开进程 HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwID); if(NULL == hProcess) { char szErr[MAX_PATH] = {0}; ::wsprintf(szErr, "Open Process Error!\nError Code:%d\n", ::GetLastError()); ::MessageBox(m_hWnd, szErr, "Error", MB_OK | MB_ICONWARNING); return ; } // 判断是32位还是64位 ::IsWow64Process(hProcess, &b32); // 获取进程的基址 GetProcessBaseAddress(&hBaseAddress, hProcess); // 根据导入表和导入表中的函数地址,暴力遍历出加载的DLL的模块基址 DWORD64 dwDllBaseAddress = GetProcessDllBaseAddress(hProcess, hBaseAddress, szDllName, b32); // 获取API函数的地址 DWORD64 dwDllFuncAddress = GetFuncInDll(hProcess, dwDllBaseAddress, szFuncName, b32); // 显示 char szTemp[MAX_PATH] = {0}; ::wsprintf(szTemp, "Dll:%s", szDllName); m_ViewList.AddString(szTemp); ::wsprintf(szTemp, "Function:%s", szFuncName); m_ViewList.AddString(szTemp); ::wsprintf(szTemp, "Image Address:0x%016I64x", dwDllFuncAddress); m_ViewList.AddString(szTemp); m_ViewList.AddString(""); } DWORD64 CViewDlg::GetFuncInDll(HANDLE hProcess, DWORD64 dwDllBaseAddress, char *lpszFuncName, BOOL b32) { DWORD dwlfanew = 0; DWORD dwFuncNameLen = ::lstrlen(lpszFuncName) + 1; char szTemp[MAX_PATH] = {0}; ::ReadProcessMemory(hProcess, (LPCVOID)(dwDllBaseAddress + 0x003c), &dwlfanew, 4, NULL); DWORD dwExportRVA = 0; // 根据32位和64位的区别,分别读取内存 // 32位 if(b32) { // 从PE头文件目录获取导出表 // 获取导出表的起始偏移 ::ReadProcessMemory(hProcess, (LPCVOID)(dwDllBaseAddress + dwlfanew + 4 + 20 + 96), &dwExportRVA, 4, NULL); } // 64位 else { // 从PE头文件目录获取导出表 // 获取导出表的起始偏移 ::ReadProcessMemory(hProcess, (LPCVOID)(dwDllBaseAddress + dwlfanew + 4 + 20 + 112), &dwExportRVA, 4, NULL); } // 获取NumberOfNames DWORD dwNumberOfNames = 0; ::ReadProcessMemory(hProcess, (LPCVOID)(dwDllBaseAddress + dwExportRVA + 24), &dwNumberOfNames, 4, NULL); // 获取AddressOfNames DWORD dwAddressOfNames = 0; ::ReadProcessMemory(hProcess, (LPCVOID)(dwDllBaseAddress + dwExportRVA + 32), &dwAddressOfNames, 4, NULL); // 遍历API函数名称并匹配 DWORD dwNameRVA = 0; for(DWORD i = 0; i < dwNumberOfNames; i++) { // 获取DLL名称的地址并读取 ::ReadProcessMemory(hProcess, (LPCVOID)(dwDllBaseAddress + dwAddressOfNames + 4*i), &dwNameRVA, 4, NULL); ::ReadProcessMemory(hProcess, (LPCVOID)(dwDllBaseAddress + dwNameRVA), szTemp, dwFuncNameLen, NULL); if(0 == ::lstrcmpi(lpszFuncName, szTemp)) // 不区分大小写 { // AddressOfNameOrdinals DWORD dwAddressOfNameOrdinals = 0; ::ReadProcessMemory(hProcess, (LPCVOID)(dwDllBaseAddress + dwExportRVA + 36), &dwAddressOfNameOrdinals, 4, NULL); WORD wHint = 0; ::ReadProcessMemory(hProcess, (LPCVOID)(dwDllBaseAddress + dwAddressOfNameOrdinals + 2*i), &wHint, 2, NULL); // AddressOfFunctions DWORD dwAddressOfFunctions = 0; ::ReadProcessMemory(hProcess, (LPCVOID)(dwDllBaseAddress + dwExportRVA + 28), &dwAddressOfFunctions, 4, NULL); DWORD dwFuncRVA = 0; ::ReadProcessMemory(hProcess, (LPCVOID)(dwDllBaseAddress + dwAddressOfFunctions + 4*wHint), &dwFuncRVA, 4, NULL); DWORD64 dwRet = dwDllBaseAddress + dwFuncRVA; return dwRet; } } return 0; }