428 lines
14 KiB
C++
428 lines
14 KiB
C++
// 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;
|
||
}
|
||
|
||
|