[C++] 代码注入非dll版
前言
昨天完成了dll注入,今天就完成了代码注入,早知道这个,就应该早点这么做。
需要注意的问题
- 64位程序只能注入64位目标程序,否则会告诉你访问错误(GetLastError() == 5)
- 经过实际操作发现Release版本能正常注入,但是Debug版本不能(卡了好久,,,我太笨了)
DLL注入和代码注入区别
- dll注入之后,dll就会一直在目标进程空间中,但是代码注入执行完成之后就消失了
- 代码注入体积小,不占内存
- 实际上我觉得可以再加一个,,,dll贼方便,,,不需要使劲考虑会不会变量地址错误的问题
代码
#include <windows.h>
#include <iostream>
#include <tlhelp32.h>
using namespace std;
// 用来传参的结构体
struct PARAM
{
FARPROC func[2]; // LoadLibraryA() GetProcAddress()
char cBuff[4][128]; // "User32.dll"、"MessageBox()"、"标题"、"内容"
};
// 定义三个函数指针(其实我理解来看就是制定了怎么格式化代码)
typedef HMODULE(*PLOADLIBRARYA)(LPCSTR);
typedef FARPROC(*PGETPROCADDRESS)(HMODULE,LPCSTR);
typedef int(*PMESSAGEBOXA)(int,LPCSTR,LPCSTR,int); // 这里应该和MessageBoxA函数的参数列表一样,但是我这样也可以
// 通过进程名获取pid
DWORD GetPidByName(LPCWSTR lpName)
{
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (!hSnap)
{
cout << "创建进程快照失败" << endl;
return 0;
}
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
Process32First(hSnap, &pe);
do
{
if (!_wcsicmp(lpName, pe.szExeFile))
{
return pe.th32ProcessID;
}
} while (Process32Next(hSnap, &pe));
return 0;
}
// 即将注入到目标进程的细作 写的这么麻烦完全是因为代码注入不能使用自己程序的资源,
// 下面用到的变量资源完全在目标进程空间
DWORD WINAPI ThreadProc(LPVOID lParam)
{
PARAM* s = (PARAM*)lParam; // 强转参数
HMODULE hmMod = ((PLOADLIBRARYA)s->func[0])(s->cBuff[0]); // 实际上是LoadLibraryA()
FARPROC pFunc = ((PGETPROCADDRESS)s->func[1])(hmMod, s->cBuff[1]); // 实际上是GetProcAddress()
((PMESSAGEBOXA)pFunc)(NULL, s->cBuff[2], s->cBuff[3], 0); // 实际上是MessageBoxA
return 0;
}
// 提权
int EnableDebugPrivilege()
{
HANDLE token;
TOKEN_PRIVILEGES tp;
// 打开进程令牌环
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
{
cout << "打开进程令牌失败" << endl;
return 0;
}
// 获取进程本地唯一ID
LUID luid;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
{
cout << "获取LUID失败" << endl;
return 0;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid = luid;
// 调整进程权限
if (!AdjustTokenPrivileges(token, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
{
cout << "提权失败" << endl;
return 0;
}
return 1;
}
int main()
{
cout << "ThreadProc地址: "<<ThreadProc << endl;
if (!EnableDebugPrivilege())
{
cout << "提权失败" << endl;
return 0;
}
DWORD dwTargetPid = GetPidByName(L"notepad.exe");
if (!dwTargetPid)
{
cout << "获取PID失败" << endl;
return 0;
}
cout << "PID: " << dwTargetPid << endl;
// 打开进程
HANDLE hTarget = OpenProcess(PROCESS_ALL_ACCESS, false, dwTargetPid);
if (!hTarget)
{
cout << "打开进程失败" << GetLastError() << endl;
return 0;
}
PARAM p;
p.func[0] = (FARPROC)LoadLibraryA; // 因为本进程已经加载了这个函数所在的模块 kernel32.dll 所以能直接得到地址
p.func[1] = (FARPROC)GetProcAddress;// 这两个在目标进程中地址也是这个,所以能直接用
// 填充参数
strcpy_s(p.cBuff[0],"User32.dll");
strcpy_s(p.cBuff[1],"MessageBoxA");
strcpy_s(p.cBuff[2],"我是细作二号,多多指教 By Startu");
strcpy_s(p.cBuff[3],"你好,");
void* pParam = nullptr;
pParam = VirtualAllocEx(hTarget, 0, sizeof(p), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (pParam == nullptr)
{
cout << "申请参数所需内存失败" << endl;
return 0;
}
if (!WriteProcessMemory(hTarget, pParam, (LPCVOID)&p, sizeof(p), NULL))
{
cout << "写入参数失败" << endl;
return 0;
}
void* pFunc = nullptr;
//DWORD dwFuncSize = (DWORD)ThreadProc - (DWORD)EnableDebugPrivilege;
DWORD dwFuncSize = 4096; // 写死函数大小,在Debug模式下,上面注释的代码会得到错误的结果
cout << "函数大小: "<<dwFuncSize << endl;
pFunc = VirtualAllocEx(hTarget,0, dwFuncSize,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
if (pFunc == nullptr)
{
cout << "申请函数内存失败" << endl;
CloseHandle(hTarget);
return 0;
}
if (!WriteProcessMemory(hTarget, pFunc, (LPCVOID)ThreadProc, dwFuncSize, NULL))
{
cout << "写入函数代码失败" << endl;
CloseHandle(hTarget);
return 0;
}
cout << "函数地址: " << pFunc << endl;
DWORD dwThreadId = 0;
HANDLE hRemoteThread = CreateRemoteThread(hTarget, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, (LPVOID)pParam, 0, &dwThreadId);
if (!hRemoteThread)
{
cout << "创建进程失败" << endl;
CloseHandle(hTarget);
return 0;
}
WaitForSingleObject(hRemoteThread,INFINITE); // 等待注入线程结束
cout << "运行结束" << hRemoteThread << endl;
CloseHandle(hTarget);
return 0;
}
- 运行之后,就能喜闻乐见的见到下面的结果了

通过x64dbg可以代码确实注入到notepad里面了 撒花★,°:.☆( ̄▽ ̄)/$:.°★ 。
解决问题过程
前面解决这个问题想了好久(笨死,,)
后来师傅说可以试试windbg调试一下试试,但是windbg是真的很难操作。。。
后来想到了OD,不过OD不能调试64位程序,幸好在两年前了解到了x64dbg,这个是个好工具,我觉得完全可以接下OD的旗帜。
- 这里 https://github.com/x64dbg/x64dbg/releases下载到x64dbg
- 然后打开记事本,使用dbg附加进程,点击选项、选项然后选择在线程入口下暂停

- OD设置位置也是这里
- 多点几次运行按钮,让notepad自己的线程先跑起来
- 然后打开代码开始注入,成功之后dbg会暂停的,一般来说就能看到下图中代码,也即是注入进去的线程函数
- F8步过,看到传参那部分没有问题,然后再call的时候(MessageBox函数),报错了,下面提示说不合法的访问(EXCEPTION_ACCESS_VIOLATION),突然想起来,应该是这里的指针指向了不合法的地址。

检查代码之后,确认参数地址都没问题,但是我直接在线程函数中调用了MessageBoxA(),这个应该就是问题的关键,一直没想到的原因,就是因为别的博文中说,“线程函数中,不可以使用Kernel32.dll和user32.dll之外的函数”,,,我理解成了,MessageBoxA是User32.dll里面的函数,所以应该可以直接使用。
那么接下来就改造一下代码,把函数也给写入进去,在线程中载入模块。也就变成了上面的成品代码。
但是依旧不行,还是会闪退,,,再通过dbg看了发现错误不一样了,他是这样的了
似乎没有看到具体代码,全是jmp,然后通过vs的汇编窗口,我看到这了
这里是所有的函数,似乎是一个目录,我通过代码中的方式获取到的地址实际上只是个jmp,注入的只是这个jmp,然后线程中,jmp了不合法的地址,就错了。
最终调成Release模式之后,就能成功运行了。这么看来 Release模式下,似乎是没有这个目录的。但是这个目录是什么还是不太清楚,了解的伙伴麻烦留个言。
参考
参考:https://www.cnblogs.com/2f28/p/9974552.html
谢谢~~
[C++] 代码注入非dll版的更多相关文章
- dll注入与代码注入
学习<逆向工程核心原理>,在x64下dll注入与代码注入. dll注入主要用到CreateRemoteThread, HANDLE WINAPI CreateRemoteThread( _ ...
- 二叉树遍历(非递归版)——python
二叉树的遍历分为广度优先遍历和深度优先遍历 广度优先遍历(breadth first traversal):又称层次遍历,从树的根节点(root)开始,从上到下从从左到右遍历整个树的节点. 深度优先遍 ...
- 代码注入——c++代码注入
代码注入之——c++代码注入 0x00 代码注入和DLL注入的区别 DLL注入后DLL会通过线程常驻在某个process中,而代码注入完成之后立即消失. 代码注入体积小,不占内存 0x01 通过c ...
- VB.NET实现32位、64位远线程运行ASM,注入非托管、托管DLL
这是一个老话题,远线程函数给我们提供了机会在其他进程中启动一个新线程,所以我们可以做很多事情.但事情远远没有结束,如果我们要做的事情非常复杂,那么将面临编写大量的ASM代码,虽然我们可以用VC之类的工 ...
- 转:EasyHook远程代码注入
EasyHook远程代码注入 最近一段时间由于使用MinHook的API挂钩不稳定,经常因为挂钩地址错误而导致宿主进程崩溃.听同事介绍了一款智能强大的挂钩引擎EasyHook.它比微软的detours ...
- 32位汇编第三讲,RadAsm,IDE的配置和使用,以及汇编代码注入方式
32位汇编第三讲,RadAsm,IDE的配置和使用,以及汇编代码注入方式 一丶RadAsm的配置和使用 用了怎么长时间的命令行方式,我们发现了几个问题 1.没有代码提醒功能 2.编写代码很慢,记不住各 ...
- 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码
详解C#泛型(二) 一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...
- 注入攻击-SQL注入和代码注入
注入攻击 OWASP将注入攻击和跨站脚本攻击(XSS)列入网络应用程序十大常见安全风险.实际上,它们会一起出现,因为 XSS 攻击依赖于注入攻击的成功.虽然这是最明显的组合关系,但是注入攻击带来的不仅 ...
- 购物车非cookie版
2015.11.26购物车,非cookie版 [点击来,你发现被骗了(笑哭,笑哭,笑哭,源代码的话,留下邮箱吧,是在不好找这一时半会儿的.)] Jsp通过反射机制获取bean中的标签,但其实,可以没有 ...
- Windows下的代码注入
木马和病毒的好坏很大程度上取决于它的隐蔽性,木马和病毒本质上也是在执行程序代码,如果采用独立进程的方式需要考虑隐藏进程否则很容易被发现,在编写这类程序的时候可以考虑将代码注入到其他进程中,借用其他进程 ...
随机推荐
- AIGC的隐私安全问题及隐私保护技术
作者:京东科技 杨博 ChatGPT 才出现两个月,就已经引起了学术界的关注.微软成为ChatGPT母公司OpenAI的合作伙伴,并确认投资百亿美元.同时,微软正计划将 OpenAI 的技术整合到其产 ...
- echarts饼图中央自定义文字
var option = { tooltip: { trigger: 'item' }, legend: { top: '5%', left: 'center' }, //中央自定义文字 title: ...
- 过滤器filters对时间格式的处理
在表格中,我们经常会对时间格式进行处理: 这个时候,我们就可以使用过滤器了. 过滤器是不会,改变原始值 {{ mess | dotime }} {{ mess | do2time }} mess: & ...
- 【解决了一个小问题】macbook m1上的docker build问题
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 1. docker hub限制的问题 因为docker b ...
- kettle系统列文章01---安装与配置
1).到官网下载需要安装的kettle版本,目前最新版本4.2,官网地址:http://kettle.pentaho.org,我们是使用的版本是kettle3.2 2).本地安装jdk 1.4或以上版 ...
- C/C++ BeaEngine 反汇编引擎
反汇编引擎有很多,这个引擎没有Dll,是纯静态链接库,适合r3-r0环境,你可以将其编译为DLL文件,驱动强制注入到游戏进程中,让其快速反汇编,读取出反汇编代码并保存为txt文本,本地分析. 地址:h ...
- 从嘉手札<2024-1-2>
最近看了很多这样的文案,某音有,某扑也有很多,出于infp的被动,莫名的觉得悲伤. 悲伤的是一颗真心没有得到珍惜, 而更令我觉得悲伤的是, 人们往往会把自己炽烈如山海一样的情感倾泻给自己心仪的对象, ...
- centos7多网口配置同网段IP解决方案
环境 CentOS Linux release 7.9.2009 (Core) 需求 服务器eth0和eth1配置同网段IP地址.掩码不配网关,同时连接两根网线,对端是两台物理隔离的交换机. 现象 给 ...
- CH32V208蓝牙从机sleep模式下功耗测试
本测试基于CH32V208W的开发板:蓝牙从机模式:使用程序BLE_UART 在进行功耗测试的时候尽量去除额外耗电器件,将开发板上的VDD于VIO相连接,测功耗时直接给VDD供电. 将会对500ms, ...
- 基于BiLSTM-CRF模型的分词、词性标注、信息抽取任务的详解,侧重模型推导细化以及LAC分词实践
基于BiLSTM-CRF模型的分词.词性标注.信息抽取任务的详解,侧重模型推导细化以及LAC分词实践 1.GRU简介 GRU(Gate Recurrent Unit)门控循环单元,是[循环神经网络]( ...

