我們在C++編程的時候,有些時候擷取更大編程餘地,以及為了縮減代碼,經常使用插入組合語言進行聯合編程。
下面我們實踐在C++中嵌入彙編實現DLL插入來源。
DLL動態函數連結庫的介面如下。
#include "stdafx.h"#include "resource.h"////////////////////////////////////////////////////////////////////////////*******全域變數聲明*******HINSTANCE hInst = NULL;HWND hDlg;//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*******函數原型聲明*******extern "C" _declspec(dllexport) void WaiGuaProc();BOOL CALLBACK DlgProc(HWND hDlg , UINT message , WPARAM wParam , LPARAM lParam);//////////////////////////////////////////////////////////////////////////BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){switch(ul_reason_for_call) {case DLL_PROCESS_ATTACH:hInst = (HINSTANCE)hModule; WaiGuaProc();break;case DLL_PROCESS_DETACH: break; } return TRUE;}extern "C" _declspec(dllexport) void WaiGuaProc(){hDlg = CreateDialog(hInst , MAKEINTRESOURCE(IDD_MAINDLG) , NULL , (DLGPROC)DlgProc);MessageBox(NULL , "Test!" , "Test" , MB_OK);return;}BOOL CALLBACK DlgProc(HWND hwndDlg, // handle to dialog box UINT uMsg, // message WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ){switch(uMsg){case WM_INITDIALOG:ShowWindow(hwndDlg , SW_SHOW);return TRUE;case WM_CLOSE:DestroyWindow(hwndDlg);return TRUE;case WM_COMMAND:if(LOWORD(wParam) == IDOK){MessageBox(NULL , "Insert Dll Success!" , "Test!" , MB_OK);}return TRUE;}return FALSE;}
下面我們進行C++與彙編聯合編程,請認真閱讀代碼注釋,
#include "Tlhelp32.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CAboutDlg dialog used for App Aboutclass CAboutDlg : public CDialog{public:CAboutDlg();// Dialog Data//{{AFX_DATA(CAboutDlg)enum { IDD = IDD_ABOUTBOX };//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CAboutDlg)protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support//}}AFX_VIRTUAL// Implementationprotected://{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD){//{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT}void CAboutDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)//{{AFX_MSG_MAP(CAboutDlg)// No message handlers//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CWaiGuaTestDlg dialogCWaiGuaTestDlg::CWaiGuaTestDlg(CWnd* pParent /*=NULL*/): CDialog(CWaiGuaTestDlg::IDD, pParent){//{{AFX_DATA_INIT(CWaiGuaTestDlg)m_ProcName = _T("");//}}AFX_DATA_INIT// Note that LoadIcon does not require a subsequent DestroyIcon in Win32m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CWaiGuaTestDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CWaiGuaTestDlg)DDX_CBString(pDX, IDC_COM_Proc, m_ProcName);//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CWaiGuaTestDlg, CDialog)//{{AFX_MSG_MAP(CWaiGuaTestDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUT_GetProc, OnBUTGetProc)ON_BN_CLICKED(IDC_BUT_EXECUTION, OnButExecution)//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CWaiGuaTestDlg message handlersBOOL CWaiGuaTestDlg::OnInitDialog(){CDialog::OnInitDialog();// Add "About..." menu item to system menu.// IDM_ABOUTBOX must be in the system command range.ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// Set the icon for this dialog. The framework does this automatically// when the application's main window is not a dialogSetIcon(m_hIcon, TRUE);// Set big iconSetIcon(m_hIcon, FALSE);// Set small icon// TODO: Add extra initialization herereturn TRUE; // return TRUE unless you set the focus to a control}void CWaiGuaTestDlg::OnSysCommand(UINT nID, LPARAM lParam){if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialog::OnSysCommand(nID, lParam);}}// If you add a minimize button to your dialog, you will need the code below// to draw the icon. For MFC applications using the document/view model,// this is automatically done for you by the framework.void CWaiGuaTestDlg::OnPaint() {if (IsIconic()){CPaintDC dc(this); // device context for paintingSendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);// Center icon in client rectangleint cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// Draw the icondc.DrawIcon(x, y, m_hIcon);}else{CDialog::OnPaint();}}// The system calls this to obtain the cursor to display while the user drags// the minimized window.HCURSOR CWaiGuaTestDlg::OnQueryDragIcon(){return (HCURSOR) m_hIcon;}void CWaiGuaTestDlg::OnBUTGetProc() {// TODO: Add your control notification handler code here((CComboBox *)GetDlgItem(IDC_COM_Proc))->ResetContent();for(int i=0 ; i < 100 ; i++)szThreadId[i] = 0;HANDLE hSnapShot;PROCESSENTRY32 szEntry;szEntry.dwSize = sizeof(PROCESSENTRY32);hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS , 0);if(hSnapShot == INVALID_HANDLE_VALUE){MessageBox("CreateToolhelp32Snapshot Error!");return;}if(Process32First(hSnapShot,&szEntry)){int i=1;((CComboBox *)GetDlgItem(IDC_COM_Proc))->AddString(szEntry.szExeFile);szThreadId[0] = szEntry.th32ProcessID;while(Process32Next(hSnapShot,&szEntry)){((CComboBox *)GetDlgItem(IDC_COM_Proc))->AddString(szEntry.szExeFile);szThreadId[i] = szEntry.th32ProcessID;i++;}MessageBox("擷取系統進程列表成功");((CComboBox *)GetDlgItem(IDC_COM_Proc))->SetCurSel(i-1);return;}}void CWaiGuaTestDlg::OnButExecution() {// TODO: Add your control notification handler code here//*******跳過遠程線程代碼,執行本程式*******goto REMOTE_THREAD_END;////////////////////////////////////////////////////////////////////////////////*******遠程線程代碼*******//////////////////////////////////////////////////////////////////////////REMOTE_THREAD_BEGIN:_asm{//*******給LoadLibrary函數地址佔位*******LoadLibraryAddr:nopnopnopnop//*******給FreeLibrary函數地址佔位*******FreeLibraryAddr:nopnopnopnop//*******給動態連結程式庫名佔位*******LibraryName:nopnopnopnopnopnopnopnop//*******代碼開始的真正位置*******REMOTE_THREAD_CODE://*******實現地址重定位,ebx儲存差值*******callrelocalrelocal:popebxsubebx , offset relocal////////////////////////////////////////////////////////////////////////////*******調用LoadLibrary*******////////////////////////////////////////////////////////////////////////////*******壓入LoadLibrary參數(動態連結程式庫名)*******moveax , ebxaddeax , offset LibraryNamepusheax//*******調用LoadLibrary*******moveax , ebxaddeax , offset LoadLibraryAddrmoveax , [eax]calleaxoreax , eaxjnzNEXT1ret////////////////////////////////////////////////////////////////////////////*******以上調用LoadLibrary*******//////////////////////////////////////////////////////////////////////////NEXT1:// *******壓入FreeLibrary參數*******pusheax// *******調用FreeLibrary*******moveax , ebxaddeax , offset FreeLibraryAddrmoveax , [eax]calleax////////////////////////////////////////////////////////////////////////////*******以上調用FreeLibrary*******//////////////////////////////////////////////////////////////////////////ret}REMOTE_THREAD_END://////////////////////////////////////////////////////////////////////////////以上為遠程線程代碼////////////////////////////////////////////////////////////////////////////*******首先擷取選中的進程控制代碼*******int nSelectedThreadId;nSelectedThreadId = ((CComboBox *)GetDlgItem(IDC_COM_Proc))->GetCurSel();nSelectedThreadId = szThreadId[nSelectedThreadId];HANDLE hSelectedProcHandle;hSelectedProcHandle = OpenProcess(PROCESS_ALL_ACCESS , FALSE , nSelectedThreadId);if(!hSelectedProcHandle){MessageBox("開啟進程失敗!");return;}// *******得到遠程線程代碼長度*******int nRemoteThreadCodeLength;_asm {moveax , offset REMOTE_THREAD_ENDmovebx , offset REMOTE_THREAD_BEGINsubeax , ebxmovnRemoteThreadCodeLength , eax}// *******在宿主進程中申請遠程線程代碼空間*******LPVOID pRemoteThreadAddr;pRemoteThreadAddr = VirtualAllocEx(hSelectedProcHandle , NULL , nRemoteThreadCodeLength , MEM_COMMIT,PAGE_EXECUTE_READWRITE);if(!pRemoteThreadAddr){MessageBox("Alloc Memory Error!");return;}//*******向宿主進程空間中複製遠程線程代碼*******LPVOIDpRemoteThreadCodeBuf;DWORDnWritenNum , nSuccess;_asm moveax , offset REMOTE_THREAD_BEGIN_asm movpRemoteThreadCodeBuf , eaxnSuccess = WriteProcessMemory(hSelectedProcHandle , pRemoteThreadAddr , pRemoteThreadCodeBuf ,nRemoteThreadCodeLength , &nWritenNum);if(!nSuccess){MessageBox("Copy Remote Thread Code Error!");return;}// *******修正遠程線程代碼*******// *******首先擷取兩個關鍵函數的地址*******HMODULE hKernel32;hKernel32 = LoadLibrary("Kernel32.dll");if(!hKernel32){MessageBox("匯入Kernel32.dll錯誤!");return;}LPVOID pLoadLibrary , pGetProcAddress , pFreeLibrary;pLoadLibrary = (LPVOID)GetProcAddress(hKernel32 , "LoadLibraryA");if(!pLoadLibrary){MessageBox("擷取LoadLibrary函數地址失敗!");return;}pGetProcAddress = (LPVOID)GetProcAddress(hKernel32 , "GetProcAddress");if(!pGetProcAddress){MessageBox("擷取GetProcAddress函數地址失敗!");return;}pFreeLibrary = (LPVOID)GetProcAddress(hKernel32 , "FreeLibrary");if(!pGetProcAddress){MessageBox("擷取FreeLibrary函數地址失敗!");return;}// *******修正代碼*******PBYTE pRemoteAddrMove;pRemoteAddrMove = (PBYTE)pRemoteThreadAddr;// *******修正LoadLibrary地址*******nSuccess = WriteProcessMemory(hSelectedProcHandle , pRemoteAddrMove , &pLoadLibrary ,4 , &nWritenNum);if(!nSuccess){MessageBox("修正LoadLibrary地址錯誤!");return;}//*******修正FreeLibrary地址*******pRemoteAddrMove +=4;nSuccess = WriteProcessMemory(hSelectedProcHandle ,pRemoteAddrMove , &pFreeLibrary ,4 ,&nWritenNum);if(!nSuccess){MessageBox("修正FreeLibrary地址錯誤!");return;}//*******傳遞動態連結程式庫名*******char szDllName[8] = {"Dll.dll"};pRemoteAddrMove +=4;nSuccess = WriteProcessMemory(hSelectedProcHandle , pRemoteAddrMove , szDllName ,8 , &nWritenNum);if(!nSuccess){MessageBox("修正GetProcAddress地址錯誤!");return;}//********把指標移動到遠程線程代碼開始處*******pRemoteAddrMove +=8;// *******建立遠程線程*******HANDLE hRemoteThreadHandle;// *******定義遠程線程函數類型*******typedef unsigned long (WINAPI *stRemoteThreadProc)(LPVOID);stRemoteThreadProc pRemoteThreadProc;// *******把入口地址賦給聲明的函數*******pRemoteThreadProc = (stRemoteThreadProc)pRemoteAddrMove;hRemoteThreadHandle = CreateRemoteThread(hSelectedProcHandle , NULL , 0 , pRemoteThreadProc , 0 , 0 , NULL);//*******測試*******CString szBuf;szBuf.Format("開始地址:%x\nLoadLibrary地址:%x\nGetProcAddress地址%x\n代碼開始地址:%x" , pRemoteThreadAddr , pLoadLibrary , pGetProcAddress , pRemoteAddrMove);MessageBox(szBuf);return;}