学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

2万

积分

41

好友

1171

主题
发表于 2020-9-1 10:54:04 | 查看: 7810| 回复: 0

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)
  下面用一个代码注入示例向notepad.exe进程注入简单的代码,注入后会弹出消息框,显示消息
  首先,运行notepad.exe 查看notepad.exe的PID,我这里显示的是2608

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)
·
  在cmd窗口中运行CodeInjection.exe 并输入命令与参数

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)
  然后可以看到一个信息框被注入到notepad.exe进程当中

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)
  下面展示一下CodeInjection.exe的源码(用VS2017编译通过)
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"

typedef struct _THREAD_PARAM
{
FARPROC pFunc[2];               // LoadLibraryA(), GetProcAddress()
char    szBuf[4][128];          // 接收传递过来的"user32.dll", "MessageBoxA", "www.xuenixiang.com", "Shin"这些字符串
} THREAD_PARAM, *PTHREAD_PARAM;

typedef HMODULE(WINAPI *PFLOADLIBRARYA)
(
LPCSTR lpLibFileName
);

typedef FARPROC(WINAPI *PFGETPROCADDRESS)//如果函数调用成功,返回值是DLL中的输出函数地址
(
HMODULE hModule,//dll模块句柄
LPCSTR lpProcName;//函数名
);

typedef int (WINAPI *PFMESSAGEBOXA)//MessageBoxA传参结构体
(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType
);

DWORD WINAPI ThreadProc(LPVOID lParam)//线程的起始地址,线程创建成功,返回非零值,否则为0
{
PTHREAD_PARAM   pParam = (PTHREAD_PARAM)lParam;//接收线程传递给函数使用的CreateThread函数lpParameter参数数据
HMODULE         hMod = NULL;
FARPROC         pFunc = NULL;

// LoadLibrary()
hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]);    // "user32.dll"
if (!hMod)
return 1;

// GetProcAddress()
pFunc = (FARPROC)((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuf[1]);  // "MessageBoxA"
if (!pFunc)
return 1;

// MessageBoxA()
((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], MB_OK);

return 0;
}

BOOL InjectCode(DWORD dwPID)//代码注入的核心部分
{
HMODULE         hMod = NULL;
THREAD_PARAM    param = { 0, };
HANDLE          hProcess = NULL;
HANDLE          hThread = NULL;
LPVOID          pRemoteBuf[2] = { 0, };
DWORD           dwSize = 0;

hMod = GetModuleHandleA("kernel32.dll");//获取kernel32.dll动态链接库的模块句柄

// set THREAD_PARAM
param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");//返回值是DLL中LoadLibraryA函数的地址
param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");
strcpy_s(param.szBuf[0], "user32.dll");
strcpy_s(param.szBuf[1], "MessageBoxA");
strcpy_s(param.szBuf[2], "www.xuenixiang.com");
strcpy_s(param.szBuf[3], "Shin");

// Open Process 打开一个已存在的进程对象,并返回进程的句柄
if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS,   // dwDesiredAccess
FALSE,                // bInheritHandle
dwPID)))             // dwProcessId
{
printf("OpenProcess() fail : err_code = %d\n", GetLastError());
return FALSE;
}

// Allocation for THREAD_PARAM
dwSize = sizeof(THREAD_PARAM);
if (!(pRemoteBuf[0] = VirtualAllocEx(hProcess,          // hProcess
NULL,                 // lpAddress
dwSize,               // dwSize
MEM_COMMIT,           // flAllocationType
PAGE_READWRITE)))    // flProtect
{
printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError());
return FALSE;
}
/*hProcess 由OpenProcess返回的进程句柄。
如参数传数据为 INVALID_HANDLE_VALUE 【即 - 1】目标进程为自身进程
lpBaseAddress要写的内存首地址
再写入之前,此函数将先检查目标地址是否可用,并能容纳待写入的数据。
lpBuffer
指向要写的数据的指针。
nSize
要写入的字节数。
返回值
非零值代表成功。
可用GetLastError获取更多的错误详细信息。*/
if (!WriteProcessMemory(hProcess,                       // hProcess
pRemoteBuf[0],                  // lpBaseAddress
(LPVOID)¶m,                 // lpBuffer
dwSize,                         // nSize
NULL))                         // [out] lpNumberOfBytesWritten
{
printf("WriteProcessMemory() fail : err_code = %d\n", GetLastError());
return FALSE;
}

// Allocation for ThreadProc() 为线程函数申请内存空间 执行成功就返回分配内存的首地址,不成功就是NULL
dwSize = (DWORD)InjectCode - (DWORD)ThreadProc;
if (!(pRemoteBuf[1] = VirtualAllocEx(hProcess,          // hProcess
NULL,                 // lpAddress
dwSize,               // dwSize
MEM_COMMIT,           // flAllocationType
PAGE_EXECUTE_READWRITE)))    // flProtect
{
printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError());
return FALSE;
}

if (!WriteProcessMemory(hProcess,                       // hProcess
pRemoteBuf[1],                  // lpBaseAddress
(LPVOID)ThreadProc,             // lpBuffer
dwSize,                         // nSize
NULL))                         // [out] lpNumberOfBytesWritten
{
printf("WriteProcessMemory() fail : err_code = %d\n", GetLastError());
return FALSE;
}

if (!(hThread = CreateRemoteThread(hProcess,            // hProcess
NULL,                // lpThreadAttributes
0,                   // dwStackSize
(LPTHREAD_START_ROUTINE)pRemoteBuf[1],     // dwStackSize
pRemoteBuf[0],       // lpParameter
0,                   // dwCreationFlags
NULL)))             // lpThreadId
{
printf("CreateRemoteThread() fail : err_code = %d\n", GetLastError());
return FALSE;
}

WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);

return TRUE;
}

BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;
//要对一个任意进程(包括系统安全进程和服务进程)进行指定了写相关的访问权的OpenProcess操作,
//只要当前进程具有SeDeDebug权限就可以了。要是一个用户是Administrator或是被给予了相应的权限,
//就可以具有该权限。可是,就算我们用Administrator帐号对一个系统安全进程执行
//OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID)还是会遇到“访问拒绝”的错误。什么原因呢?
//原来在默认的情况下进程的一些访问权限是没有被启用(Enabled)的,所以我们要做的首先是启用这些权限。
//与此相关的一些API函数有OpenProcessToken、LookupPrivilegevalue、AdjustTokenPrivileges。
//我们要修改一个进程的访问令牌,首先要获得进程访问令牌的句柄,这可以通过OpenProcessToken得到
if (!OpenProcessToken(GetCurrentProcess(),//用来打开与进程相关联的访问令牌
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken))
{
printf("OpenProcessToken error: %u\n", GetLastError());
return FALSE;
}

if (!LookupPrivilegeValue(NULL,           // lookup privilege on local system
lpszPrivilege,  // privilege to lookup 
&luid))        // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError());
return FALSE;
}

tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;

// Enable the privilege or disable all privileges.
if (!AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError());
return FALSE;
}

if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}

return TRUE;
}

int main(int argc, char *argv[])
{
DWORD dwPID = 0;

if (argc != 2)
{
printf("\n USAGE  : %s <pid>\n", argv[0]);
return 1;
}

// change privilege
if (!SetPrivilege(SE_DEBUG_NAME, TRUE))
return 1;

// code injection
dwPID = (DWORD)atol(argv[1]);
InjectCode(dwPID);

return 0;
}

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)
  InjectCode()是代码注入技术的核心部分。两次调用VirtualAllocEx和WriteProcessMemory,第一次调用分配内存空间并写入远程线程的数据,第二次调用分配内存空间并写入远程线程的代码。这是代码注入的一个非常重要的特征
  下面动态调试代码注入的过程
  首先用OD调试notepad.exe ,F9跑起来

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)
  然后设置OD,选项 调试设置 勾选中断于新线程

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)
  现在开始,每当notepad.exe进程中生成新的线程,调试器就暂停在线程函数开始的代码位置,现在运行CodeInjection.exe,输入相应的PID

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)
  [esp+8]就是Iparam参数

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)
  插入到notepad.exe进程的汇编代码(宏观)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)
  高级语言中函数大小的计算方法类似于汇编语言中代码所占空间的计算方法(详情可以百度或者查阅《计算机组成原理和汇编语言》一书)

【windows代码注入教程】第五课 代码注入(C语言)

【windows代码注入教程】第五课 代码注入(C语言)
            
温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046

小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

GMT+8, 2024-12-28 00:34 , Processed in 0.200404 second(s), 42 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表