远程线程注入(先简单说,下面会详细说)
今天整理下代码注入(远程线程注入),所谓代码注入,可以简单的理解为是在指定内进程里申请一块内存,然后把我们自己的执行代码和一些变量拷贝进去(通常是以启线程的方式),然后直接调用对方内存里我们拷贝进去的那部分代码(创建一个线程)。这样就行了,此时我们的这个线程就是目标进程的子线程了。但是要注意一点,代码注入之所以能成功重点是:有些系统常用的dll里的某些函数,在不同的进程里面获取到的地址是一样的(此处注意,一样的概念是指数值一样,但是这个数值存的地方不一样。也就是A里面的b变量的值等于C里面的d变量的值。这个要清楚,不然在学习API劫持的时候可能会迷茫)。

首先先介绍几个需要的API

1.LoadLibrary()  和  GetProcAddress() 

    这两个函数,一个是加载dll库,一个是从已经加载的库句柄里拿出来某个函数的地址,可以理解成是把一个dll加到内存里,然后获取里面某个函数的地址,得到这个地址后就可以直接调用了,这两个简单的函数经常用到,无论是常规调用还是静态免杀都经常用。
2.OpenProcess() 

    根据进程id获取进程的句柄,也就是获取进程操控权。
3.VirtualAllocEx()

    在指定进程里开辟一块内存,用于存放自己的代码和参数。
4.WriteProcessMemory()

    3里面的函数会在一个进程里开辟一块内存,然后在那个内存里直接用本函数4进行数据写入,就是在别人那开一块内存然后写自己的东西。
5.CreateRemoteThread()

    最核心的函数,在指定进程的某个内存位置存储的函数为线程函数,启动一个线程,当然被启动的这个线程属于指定的这个进程。

    OK上面那5个API就是代码注入需要的几个基本的了,接下来我说一下我对线程注入的理解:

线程注入其实很好理解,就是说我们通过一定的手段在宿主也就是需要被注入的进程那获取权限,得到权限之后我们要在这个进程上开辟一定的内存,然后把自己的线程函数内容以及参数什么的全都拷贝过去,这样目标进程上有我们的函数,我们的参数,我们这个时候只是需要"帮"它启动一下这个线程就OK了,直接用CreateRemoteThread函数在对方进程的某个内存位置的某个线程函数作为线程函数启动。

然后上面的那个解释是宏观的,也就是泛泛而谈,最最核心的思路是这样:对于每个进程,他们调用的API大多都是自己随时调用随时获取的,地址也不一样,但是只有极少数的几个系统核心dll他们不一样,系统为了优化和统一管理,使得每个人load的dll然后从里面获取的函数地址是一样的,也就是大家共用一套已经被载入的dll地址,可以用的也是用的最多的就是User32.dll,kernel32.dll(我目前就知道这两个,但是不重要只要知道一个kernel32.dll然后在里面做一个工厂就行了),既然大家用的地址都一样,那么也就是说我在我本地直接获取里面某个函数的地址,那么你的地址也是这个,那我直接帮你“怂恿”你去执行就行了呗。这样代码注入的思路可以总结成是:我们以所有进程加载的某些DLL地址是相同的,通过这个相同为跳板,“跳过去,然后帮宿主进程做事”,这样想来有点局限,因为只有那么可怜的几个dll大家的地址一样,但是不用担心,我下面会介绍一个我自创的思路,就是在宿主里面建造一个工厂,然后加载任意想加载的东西,如果我们每个产品都要自己生产,然后送货,但是因为有很多货是不合格的,都被扣押了,那么我们为什么不直接生产一个合格的工厂送过去,只要工厂被接受了,那么他所生产的所有产品都被接受了,也就是在宿主进程上加载的dll里面的api肯定和他自己加载的一样啊,这样突破了常规代码注入函数受限制的弊端,下面注意问题的4还会说这个问题。

需要注意的问题:

1.

    参数结构体的结构体名字有说道,我之前没注意这个问题,造成一定概率的注入失败。

2.

    注意64位32位问题,目前的经验是64位的话就用64位程序注入,32位就用32位程序注入,这个应该可以解决,问题出现在获取进程pid那。

3.

    注意一个非常关键的问题,在代码注入的时候,你所需要的任何变量最好自己以内存拷贝的方式传过去,比如我直接在线程函数里开了一个变量 char[512] = "00000",当你把这个函数地址拷贝到指定进程里面去的时候,个"00000"所占的内容并没有被拷贝过去,这样你在调用的时候内存就会出错。

4.

    代码注入限制非常多,被注入的线程函数里面内容非常有讲究,大小有限制,存储方式有限制,不能随便调用API函数,比如直接在里面来了一个Sleep(1000),你觉得这个函数是系统的,在那都能调用,然而并不是,直接就内存错误,如果需要,你需要找到对应的API然后加载进去,然后调用,但是又不是所有的AIP函数地址都是统一的,那么怎么办?我之前有一个解决办法是直接导入两个固定的地址LoadLibrary()  和  GetProcAddress(),通常的代码注入者的固定思路是靠这两个函数获取地址然后传过去,然而大家很容易忽略一个思路,就是既然我们知道所有程序的LoadLibrary()
 和  GetProcAddress() 地址是一样的,那么我们就直接本地获取这两个函数的地址,然后把这两个地址传到线程函数里,然后在里面在本地生产相应的函数,这样我们加载的API都是目标线程能接受的API地址了,这个思路是当时睡觉时候想的,妈的激动地差点失眠(虽然现在回头整理这些的时候已经不怎么激动了)。

5.

    还有很多限制和注意问题,这里就不多说了,需要的可以自己去查一查,我知道的也不多,有的时候也是现用现查。

    OK上面是需要知道的思路和基础,下面就直接说实现。

    思路大体分这么几个阶段
1.提权              权限不够的话可能到导致敏感函数执行失败。

2.获取pid         获取宿主进程的pid

3.打开宿主进程    可以理解成是获取宿主进程的操控权,当然这一步依赖于1的提权和2获取的pid

4.初始化参数数据  这一步就是得到一些AIP地址了,参数了什么的,然后把它存在参数的结构体里。

5.在宿主进程里分配内存用于存放参数

6.把需要的参数全都拷贝到宿主继承内存里(第4步获取的内存位置)

7.在宿主进程里分配内存用于存放线程函数代码

8.把线程函数直接拷到7获取的内存里

9.启动注入宿主进程的线程

10.善后,释放一下垃圾什么的。

下面我给出一个最基本的代码注入的代码,功能是在qq或者explorer里面注入一个线程,线程就只是弹出来一个对话框(我资源里整理了一个测试项目http://download.csdn.net/detail/u013761036/9603026)。

.H
#pragma once
#include <Windows.h>
#include <stdlib.h>
#include <tlhelp32.h>
#include <Psapi.h>
#include <string> using std::string;
using std::wstring; #pragma comment (lib,"Psapi.lib") #pragma warning(disable:4996) class CInjection
{
private:
bool AdjustProcessTokenPrivilege();//提权 bool Camp2str(wstring wsStrA ,wstring wsStrB);
DWORD GetProcessIdByName(const wstring &wsProcessName);//获取pid public:
bool InjectionExeAndShowMessage(const wstring &wsProcessName);
}; .CPP
#include "stdafx.h"
#include "Injection.h" typedef struct _REMOTE_PARAMETER
{
CHAR cTitle[64];
CHAR cBody[64];
DWORD dwMessAgeBoxShowAddress;
}RemotePara ,* PRemotePara; bool CInjection::AdjustProcessTokenPrivilege()
{
LUID luidTmp;
HANDLE hToken;
TOKEN_PRIVILEGES tkp; if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return false; if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidTmp))
{
CloseHandle(hToken);
return FALSE;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = luidTmp;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if(!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
{
CloseHandle(hToken);
return FALSE;
}
return true;
} bool CInjection::Camp2str(wstring wsStrA ,wstring wsStrB)
{
int nSize = wsStrA.length();
for(int i = 0 ;i < nSize ;i ++)
{
if(wsStrA[i] >= 'A' && wsStrA[i] <= 'Z')
wsStrA[i] += 'a'- 'A';
} nSize = wsStrB.length();
for(int i = 0 ;i < nSize ;i ++)
{
if(wsStrB[i] >= 'A' && wsStrB[i] <= 'Z')
wsStrB[i] += 'a'- 'A';
} return wsStrA == wsStrB;
} DWORD CInjection::GetProcessIdByName(const wstring &wsProcessName)
{
HANDLE hProcess = 0;
DWORD dwProcess[2048] ,dwNeeded;
TCHAR tcProcName[MAX_PATH] = {0};
wstring wsNowProcessName = L"";
int nTempSize = 0;
int nPos = 0; EnumProcesses(dwProcess, sizeof(dwProcess), &dwNeeded); for(int i = 0 ;i < dwNeeded / sizeof(DWORD) ;i++)
{
if(0 != dwProcess[i])
{
hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcess[i]);
GetModuleFileNameEx(hProcess, NULL, tcProcName, MAX_PATH);
nPos = wstring(tcProcName).find_last_of(L'\\');
if(nPos != wstring::npos)
{
wsNowProcessName = wstring(wstring(tcProcName).substr(nPos + 1));
if(Camp2str(wsProcessName ,wsNowProcessName))
{
DWORD aa = dwProcess[i];
return aa;
}
//if(wsProcessName == wsNowProcessName)
// return dwProcess[i];
}
}
}
return 0;
} //注入的线程函数
static DWORD __stdcall RemoteThread(PRemotePara myData)
{
typedef int (WINAPI *_MessageBoxA)(
_In_opt_ HWND hWnd,
_In_opt_ LPCSTR lpText,
_In_opt_ LPCSTR lpCaption,
_In_ UINT uType
);
_MessageBoxA mbAdd = (_MessageBoxA)myData->dwMessAgeBoxShowAddress;
mbAdd(NULL ,myData->cBody ,myData->cTitle ,MB_OK);
return 0;
} bool CInjection::InjectionExeAndShowMessage(const wstring &wsProcessName)
{
//1.提权
if(!AdjustProcessTokenPrivilege())
return false; //2.获取pid
DWORD dwProPID = 0;
if((dwProPID = GetProcessIdByName(wsProcessName)) == 0)
return false; //3.打开进程
HANDLE hProcess = NULL;
if((hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE ,dwProPID)) == NULL)
return false; //4.初始化参数数据
RemotePara rpData = {0};
ZeroMemory(&rpData,sizeof(RemotePara));
HINSTANCE hInst=NULL;
hInst=LoadLibrary(L"User32.dll");
if(hInst == NULL)
return false;
rpData.dwMessAgeBoxShowAddress = 0;
rpData.dwMessAgeBoxShowAddress = (DWORD)GetProcAddress(hInst,"MessageBoxA");
if(rpData.dwMessAgeBoxShowAddress == 0)
return false;
FreeLibrary(hInst);
strcat(rpData.cTitle ,"title");
strcat(rpData.cBody ,"body");
//RemoteThread(&rpData); //5.在宿主进程里分配内存,用于存参数
PRemotePara pPara = NULL;
pPara = (PRemotePara)VirtualAllocEx(hProcess , 0 ,sizeof(RemotePara) ,MEM_COMMIT,PAGE_READWRITE);
if(pPara == NULL) return false; //6.把参数写入宿主进程里,注意结构体的命名(_REMOTE_PARAMETER)
if(!WriteProcessMemory(hProcess ,pPara ,&rpData ,sizeof(RemotePara) ,0))
return false; //7.在宿主进程里分配内存,用于写线程函数 1024这个值是我随意填写的,我觉得这么大可以存下上面那个线程函数
void *pRemoteThr = VirtualAllocEx(hProcess , NULL ,1024 ,MEM_COMMIT | MEM_RESERVE ,PAGE_EXECUTE_READWRITE);
if(pRemoteThr == NULL) return false; //8.把进程函数写入分配的内存里
if(!WriteProcessMemory(hProcess ,pRemoteThr ,&RemoteThread ,1024 ,0))
return false; //9.启动注入宿主进程的进程
DWORD dwThreadId = 0;
HANDLE hThread = CreateRemoteThread(hProcess ,0 ,0 ,(DWORD (WINAPI *)(LPVOID))pRemoteThr ,pPara ,0 ,&dwThreadId);
if(!hThread) return false; //10.等待线程结束,然后清理内存 WaitForSingleObject(hThread ,INFINITE);
CloseHandle(hThread);
VirtualFreeEx(hProcess ,pPara ,0 ,MEM_RELEASE);
VirtualFreeEx(hProcess ,pRemoteThr ,0 ,MEM_RELEASE);
CloseHandle(hProcess);
return true;
} USER
#include "stdafx.h"
#include "ZZZTest.h"
#include "Injection.h" int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
CInjection *pciTest = new CInjection();
pciTest->InjectionExeAndShowMessage(L"qq.exe"); //explorer.exe
delete pciTest;
return 0;
}

windows-CODE注入(远程线程注入)的更多相关文章

  1. windows:shellcode 远程线程hook/注入(一)

    https://www.cnblogs.com/theseventhson/p/13199381.html 上次分享了通过APC注入方式,让目标线程运行shellcode.这么做有个前提条件:目标线程 ...

  2. 远程线程注入方法CreateRemoteThread

    最近在整理学习Windows注入方面的知识,这个远程注入前面早写过,现在看看人家博客的理解整理,整理, 需要源码的可以到我的github上下载. 链接是  https://github.com/Ars ...

  3. 安全之路 —— 借助DLL进行远程线程注入实现穿墙与隐藏进程

    简介        大多数后门或病毒要想初步实现隐藏进程,即不被像任务管理器这样典型的RING3级进程管理器找到过于明显的不明进程,其中比较著名的方法就是通过远程线程注入的方法注入将恶意进程的DLL文 ...

  4. 安全之路 —— 无DLL文件实现远程线程注入

    简介         在之前的章节中,笔者曾介绍过有关于远程线程注入的知识,将后门.dll文件注入explorer.exe中实现绕过防火墙反弹后门.但一个.exe文件总要在注入时捎上一个.dll文件着 ...

  5. 详细解读:远程线程注入DLL到PC版微信

    一.远程线程注入的原理 1.其基础是在 Windows 系统中,每个 .exe 文件在双击打开时都会加载 kernel32.dll 这个系统模块,该模块中有一个 LoadLibrary() 函数,可以 ...

  6. 远程线程注入dll,突破session 0

    前言 之前已经提到过,远线程注入和内存写入隐藏模块,今天介绍突破session 0的dll注入 其实今天写这个的主要原因就是看到倾旋大佬有篇文章提到:有些反病毒引擎限制从lsass中dump出缓存,可 ...

  7. mfc HackerTools远程线程注入

    在一个进程中,调用CreateThread或CreateRemoteThreadEx函数,在另一个进程内创建一个线程(因为不在同一个进程中,所以叫做远程线程).创建的线程一般为Windows API函 ...

  8. 远程线程注入DLL突破session 0 隔离

    远程线程注入DLL突破session 0 隔离 0x00 前言 补充上篇的远程线程注入,突破系统SESSION 0 隔离,向系统服务进程中注入DLL. 0x01 介绍 通过CreateRemoteTh ...

  9. 远程线程注入DLL

    远程线程注入 0x00 前言 远程线程注入是一种经典的DLL注入技术.其实就是指一个新进程中另一个进程中创建线程的技术. 0x01 介绍 1.远程线程注入原理 画了一个图大致理解了下远程线程注入dll ...

随机推荐

  1. Java入门和环境配置ideaJ安装

    Java入门及环境搭建 目录 Java入门及环境搭建 什么是Java Java Java的发展 Java的特性和优势 Java三大版本 JDK JRE JVM JAVA开发环境搭建 安装JDK 卸载J ...

  2. 关于主机不能访问虚拟机的web服务解决

    centos7默认并没有开启80端口,我们只有开启就行 [root@localhost sysconfig]# firewall-cmd --permanent --add-port=3032/tcp ...

  3. LNMP配置——Nginx配置 —— Nginx解析PHP

    一.配置 #vi /usr/local/nginx/conf/vhost/test.com.conf 写入: server { listen 80; server_name test.com test ...

  4. 使用代码生成工具快速开发ABP框架项目

    在一般系统开发中,我们一般要借助于高度定制化的代码生成工具,用于统一代码风,节省开发时间,提高开发效率.不同的项目,它的项目不同分层的基类定义不同,我们需要在框架基类的基础上扩展我们的业务类代码,尽量 ...

  5. css整理之-----------技巧、黑魔法

    css 看起来比较简单,但是要想做的好也不是那么容易,我们在平时开发中,主要用css 来美化我们的html结构,所有我觉得css 还是挺重要的,这里记录整理一些关于css 的技巧以及容易忘记的知识点. ...

  6. JavaCV 采集摄像头及桌面视频数据

    javacv 封装了javacpp-presets库很多native API,简化了开发,对java程序员来说比较友好. 之前使用JavaCV库都是使用ffmpeg native API开发,这种方式 ...

  7. linux下 > /dev/null 2 > &1 的意思和如何在后台启动进程

    一.几个基本符号及其含义 之前看到别人写的一个shell脚本,有一个命令是:rm -f ${src_tmp_file} > /dev/null 2>&1 现在大概明白是什么意思了 ...

  8. 解析库--XPath

    from lxml import etree 2 text = ''' 3 <div> 4 <ul> 5 <li class = "item-0"&g ...

  9. 微信小程序应用开发-手动创建

    基础知识: index.wxml的代码为 Html,有很多标签,如等 index.wwss相当于css 即样式 index.js中有很多函数,可自定义 操作步骤: 删除app.json文件中page/ ...

  10. 【linux】驱动-1-环境准备

    目录 前言 1. 开发环境搭建 1.1 环境准备 1.1.1 安装工具 1.1.2 编译内核 1.1.2.1 获取内核源码 1.1.2.2 编译内核 1.2 内核驱动模块编译和加载 1.2.1 hel ...