本文共 12449 字,大约阅读时间需要 41 分钟。
原理:
通过以挂起的方式创建进程对其注入。#include#include #include #include typedef struct Param{ DWORD year; DWORD Month; DWORD Day; FARPROC pFun[2];}Param,*pParam;void _declspec(naked) AddTimelimit(pParam param){ _asm { pushfd push eax push ecx push edx push ebx sub esp, 0x18 lea eax, ss:[esp + 0x6] push eax mov ebx,[esp+0x34] //保存param结构体指针 call ds:[ebx+0xc] lea eax, ss : [esp + 0x6] mov cx, word ptr ss : [esp + 0x6] mov word ptr ss : [esp], cx mov cx, word ptr ss : [esp + 0x8] mov word ptr ss : [esp + 2], cx mov cx, word ptr ss : [esp + 0xc] mov word ptr ss : [esp + 4], cx mov eax, ss : [ebx] mov ecx, ss : [ebx + 0x4] mov edx, ss : [ebx + 0x8] cmp word ptr ss : [esp], ax ja _Label_exit cmp word ptr ss : [esp + 2], cx ja _Label_exit cmp word ptr ss : [esp + 4], dx ja _Label_exit add esp, 0x18 pop ebx pop edx pop ecx pop eax popfd retn _Label_exit : push 0 call ds : [ebx + 0x10] retn }} //code的原型BYTE code[] = { 0x9C,0x68,0x00,0x00,0x00,0x00,0x50,0x51,0x52,0x53,0x83,0xEC,0x18,0x36,0x8D, 0x44,0x24,0x06,0x50,0x8B,0x5C,0x24,0x2C,0x3E,0xFF,0x53,0x0C,0x36,0x8D,0x44,0x24,0x06,0x36,0x66,0x8B, 0x4C,0x24,0x06,0x36,0x66,0x89,0x0C,0x24,0x36,0x66,0x8B,0x4C,0x24,0x08,0x36, 0x66,0x89,0x4C,0x24,0x02,0x36,0x66,0x8B,0x4C,0x24,0x0C,0x36,0x66,0x89,0x4C, 0x24,0x04,0x36,0x8B,0x03,0x36,0x8B,0x4B,0x04,0x36,0x8B,0x53,0x08,0x36,0x66, 0x39,0x04,0x24,0x77,0x1E,0x36,0x66,0x39,0x4C,0x24,0x02,0x77,0x16,0x36,0x66, 0x39,0x54,0x24,0x04,0x77,0x0E,0x83,0xC4,0x18,0x5B,0x5A,0x59,0x58,0x9D,0x9D, 0x55,0x8B,0xEC,0xE9,0x00,0x00,0x00,0x00,0x6A,0x00,0x3E,0xFF,0x53,0x10,0xC2,0x04,0x00};BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) //提升程序权限{ TOKEN_PRIVILEGES tp; HANDLE hToken; LUID luid; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) //获取令牌句柄 { _tprintf(TEXT("OpenProcessToken error : %u\n"), GetLastError()); return FALSE; } LookupPrivilegeValue(NULL, lpszPrivilege, &luid); //获取指定权限的LUID tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; if (bEnablePrivilege) tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; else tp.Privileges[0].Attributes = 0; if (!AdjustTokenPrivileges(hToken, //令牌句柄 FALSE, //FALSE则修改权限 &tp, //令牌权限的结构(包括LUID和tp中的数组个数吗) sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) { _tprintf(TEXT("AdjustTokenPrivileges error : %u\n"), GetLastError()); return FALSE; } //调整进程的权限 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) { _tprintf(TEXT("The Token does not have the specified privilege. \n")); return FALSE; } return TRUE;}void main(){ STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; LPVOID pRemoteParam,pRemoteFun, pBuf_user32; Param param = {0}; DWORD dwBufSize,dwTemp; BYTE mbxBuffer[5] = { 0 }, Buf_user32[] = "user32.dll", jmpcode[5] = { 0xE9,0,0,0,0 }, shellcode[100] = { 0x50,0x9C,0x68,0x00,0x00,0x1C,0x00,0xE8,0xC4,0xD8,0xDC,0x75,0xE8, 0x0F,0x1A,0x79,0x75,0x50,0xE8,0xE9,0xEC,0xDC,0x75,0x9D,0x58,0xE9, 0xD3,0xAE,0xAD,0x77 }; FARPROC Address_mbx = GetProcAddress(LoadLibraryA("user32.dll") , "CreateWindowExA"); DWORD OldProtect = 0; BYTE *pShellcode; param.year = 2018; param.Month = 2; param.Day = 1; param.pFun[0] = GetProcAddress(GetModuleHandle("kernel32.dll"),"GetLocalTime"); param.pFun[1] = GetProcAddress(GetModuleHandle("kernel32.dll"), "ExitProcess"); SetPrivilege(SE_DEBUG_NAME, TRUE); CreateProcessA("需要挂起的程序路径", NULL, NULL,NULL,NULL,CREATE_SUSPENDED,NULL,NULL,&si,&pi); //写入参数到目标进程 dwBufSize = sizeof(param); pRemoteParam = VirtualAllocEx(pi.hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(pi.hProcess,pRemoteParam,(LPVOID)¶m,dwBufSize,NULL); //写入shellcode到目标进程 dwBufSize = 127; pRemoteFun = VirtualAllocEx(pi.hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(&code[2], &pRemoteParam, 4); dwTemp = (DWORD)Address_mbx + 5 - (DWORD)pRemoteFun - 113 - 5; memcpy(&code[114], &dwTemp, 4); WriteProcessMemory(pi.hProcess, pRemoteFun, (LPVOID)code, dwBufSize, NULL); //不sleep就会出现读取不到的297错误 Sleep(50); //获取线程上下文 CONTEXT ct = { 0 }; ct.ContextFlags = CONTEXT_CONTROL; GetThreadContext(pi.hThread, &ct); printf("ct.eip = %X", ct.Eip); //读取挂起位置,供写入shellcode使用 dwBufSize = sizeof(Buf_user32); pBuf_user32 = VirtualAllocEx(pi.hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); WriteProcessMemory(pi.hProcess, pBuf_user32, (LPVOID)Buf_user32, dwBufSize, NULL); //为shellcode分配100字节空间并写入 pShellcode = (BYTE *)VirtualAllocEx(pi.hProcess, NULL, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE); dwTemp = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA") - (DWORD)pShellcode - 5 -7; //push eax memcpy(&shellcode[3],&pBuf_user32,4); //call LoadlibraryA memcpy(&shellcode[8], &dwTemp, 4); //pushfd dwTemp = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetCurrentThread") - (DWORD)pShellcode - 5 - 12; //push add_of_user32.dll memcpy(&shellcode[13], &dwTemp, 4); dwTemp = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "SuspendThread") - (DWORD)pShellcode - 5 - 18; memcpy(&shellcode[19], &dwTemp, 4); dwTemp = ct.Eip - 5 - (DWORD)pShellcode - 25; memcpy(&shellcode[26],&dwTemp,4); WriteProcessMemory(pi.hProcess,pShellcode,shellcode,100,NULL); ct.Eip = (DWORD)pShellcode; SetThreadContext(pi.hThread,&ct); ResumeThread(pi.hThread); Sleep(50); VirtualProtectEx(pi.hProcess,(LPVOID)Address_mbx,10,PAGE_EXECUTE_READWRITE,&OldProtect); //printf("err = %d", GetLastError()); ReadProcessMemory(pi.hProcess, (LPVOID)Address_mbx,(LPVOID)mbxBuffer,10,NULL); //printf("err = %d", GetLastError()); DWORD offset = (DWORD)pRemoteFun - (DWORD)Address_mbx - 5; memcpy(&jmpcode[1], &offset, 4); WriteProcessMemory(pi.hProcess,(LPVOID)Address_mbx,jmpcode,5,NULL); ResumeThread(pi.hThread); //恢复shellcode里挂起的线程}
// ProcessInject.h
#pragma once// ProcessInject 对话框class ProcessInject : public CDialogEx{ DECLARE_DYNAMIC(ProcessInject)public: ProcessInject(CWnd* pParent = NULL); // 标准构造函数 virtual ~ProcessInject();// 对话框数据 enum { IDD = IDD_DIALOG3 };protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP()public: CString m_strExePath; CString m_strDllPath; afx_msg void OnBnClickedInject(); afx_msg void OnBnClickedFreemem(); afx_msg void OnBnClickedButton3(); afx_msg void OnBnClickedButton4();};
// ProcessInject.cpp
// ProcessInject.cpp : 实现文件//#include "stdafx.h"#include "MyInjectTool.h"#include "ProcessInject.h"#include "afxdialogex.h"//ShellCode结构体//结构必须字节对齐1#pragma pack(1) typedef struct _INJECT_CODE{ BYTE byPUSH; DWORD dwPUSH_VALUE; BYTE byPUSHFD; BYTE byPUSHAD; BYTE byMOV_EAX; //mov eax, addr szDllpath DWORD dwMOV_EAX_VALUE; BYTE byPUSH_EAX; //push eax BYTE byMOV_ECX; //mov ecx, LoadLibrary DWORD dwMOV_ECX_VALUE; WORD wCALL_ECX; //call ecx BYTE byPOPAD; BYTE byPOPFD; BYTE byRETN; CHAR szDllPath[MAX_PATH];}INJECT_CODE, *PINJECT_CODE;#pragma pack() // ProcessInject 对话框IMPLEMENT_DYNAMIC(ProcessInject, CDialogEx)ProcessInject::ProcessInject(CWnd* pParent /*=NULL*/) : CDialogEx(ProcessInject::IDD, pParent) , m_strExePath(_T("")) , m_strDllPath(_T("")){}ProcessInject::~ProcessInject(){}void ProcessInject::DoDataExchange(CDataExchange* pDX){ CDialogEx::DoDataExchange(pDX); DDX_Text(pDX, IDC_EDIT1, m_strExePath); DDX_Text(pDX, IDC_EDIT2, m_strDllPath);}BEGIN_MESSAGE_MAP(ProcessInject, CDialogEx) ON_BN_CLICKED(IDC_INJECT, &ProcessInject::OnBnClickedInject) ON_BN_CLICKED(IDC_FREEMEM, &ProcessInject::OnBnClickedFreemem) ON_BN_CLICKED(IDC_BUTTON3, &ProcessInject::OnBnClickedButton3) ON_BN_CLICKED(IDC_BUTTON4, &ProcessInject::OnBnClickedButton4)END_MESSAGE_MAP()// ProcessInject 消息处理程序HANDLE g_hProcess1 = NULL;LPVOID g_lpBuffer1 = NULL;void ProcessInject::OnBnClickedInject(){ // TODO: 在此添加控件通知处理程序代码 // TODO: 在此添加控件通知处理程序代码 BOOL bRet = FALSE; STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; CONTEXT oldContext = { 0 }; CONTEXT newContext = { 0 }; INJECT_CODE ic = { 0 }; DWORD dwOldEip = 0; si.wShowWindow = SW_SHOWDEFAULT; si.cb = sizeof(PROCESS_INFORMATION); HANDLE hThread = NULL; //以挂起的方式创建进程 bRet = CreateProcess(m_strExePath.GetBuffer(0), NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); if (!bRet) { MessageBox("CreateProcess 失败"); return; } g_hProcess1 = pi.hProcess; hThread = pi.hThread; //申请内存 g_lpBuffer1 = VirtualAllocEx(g_hProcess1, NULL, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (g_lpBuffer1 == NULL) { MessageBox("VirtualAllocEx 失败"); return; } //给ShellCode结构体赋值 ic.byPUSH = 0x68; ic.dwPUSH_VALUE = 0x12345678; ic.byPUSHFD = 0x9C; ic.byPUSHAD = 0x60; ic.byMOV_EAX = 0xB8; ic.dwMOV_EAX_VALUE = (DWORD)g_lpBuffer1 + offsetof(INJECT_CODE, szDllPath); ic.byPUSH_EAX = 0x50; ic.byMOV_ECX = 0xB9; ic.dwMOV_ECX_VALUE = (DWORD)&LoadLibrary; ic.wCALL_ECX = 0xD1FF; ic.byPOPAD = 0x61; ic.byPOPFD = 0x9D; ic.byRETN = 0xC3; memcpy(ic.szDllPath, m_strDllPath.GetBuffer(0), m_strDllPath.GetLength()); //写入ShellCode bRet = WriteProcessMemory(g_hProcess1, g_lpBuffer1, &ic, sizeof(ic), NULL); if (!bRet) { MessageBox("写入内存失败"); return; } //获取线程上下文 oldContext.ContextFlags = CONTEXT_FULL; bRet = GetThreadContext(hThread, &oldContext); if (!bRet) { MessageBox("GetThreadContext 失败"); return; } newContext = oldContext;#ifdef _WIN64 newContext.Rip = (DWORD)g_lpBuffer1; dwOldEip = newContext.Rip;#else newContext.Eip = (DWORD)g_lpBuffer1; dwOldEip = newContext.Eip;#endif //;将指针指向ShellCode第一句push 12345678h中的地址,写入返回地址 bRet = WriteProcessMemory(g_hProcess1, ((char*)g_lpBuffer1) + 1, &dwOldEip, sizeof(DWORD), NULL); if (!bRet) { MessageBox("写入内存失败"); return; } bRet = SetThreadContext(hThread, &newContext); if (!bRet) { MessageBox("SetThreadContext 失败"); return; } //然后把主线程跑起来 bRet = ResumeThread(hThread); if (bRet == -1) { MessageBox("ResumeThread 失败"); return; }}void ProcessInject::OnBnClickedFreemem(){ // TODO: 在此添加控件通知处理程序代码 if (!VirtualFreeEx(g_hProcess1, g_lpBuffer1, 0, MEM_RELEASE)) { MessageBox("VirtualFreeEx 失败"); return; } MessageBox("释放对方空间成功");}void ProcessInject::OnBnClickedButton3(){ // TODO: 在此添加控件通知处理程序代码 char szFilter[] = "可执行程序|*.exe"; CFileDialog fileDlg(TRUE, "exe", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter); UpdateData(TRUE); if (fileDlg.DoModal() == IDOK) { m_strExePath = fileDlg.GetPathName(); } UpdateData(FALSE);}void ProcessInject::OnBnClickedButton4(){ // TODO: 在此添加控件通知处理程序代码 char szFilter[] = "动态链接库|*.dll"; CFileDialog fileDlg(TRUE, "dll", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter); UpdateData(TRUE); if (fileDlg.DoModal() == IDOK) { m_strDllPath = fileDlg.GetPathName(); } UpdateData(FALSE);}
转载于:https://blog.51cto.com/haidragon/2306923