原理:
通过以挂起的方式创建进程对其注入。
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include<tchar.h>
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);
}
©著作权归作者所有:来自51CTO博客作者土匪猿的原创作品,如需转载,请注明出处,否则将追究法律责任