DemonMemory/源代码/ViewDlg.cpp

428 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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;
}