对于擦除模块痕迹,我实验了两种方法,下面一一阐述:
1.修改PEB结构,用代码说话
typedef
struct
_PEB_LDR_DATA

...
{
ULONG Length;
BOOLEAN Initialized;
BYTE reserved[3];
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
}
PEB_LDR_DATA,
*
PPEB_LDR_DATA;

typedef
struct
_UNICODE_STRING

...
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
}
UNICODE_STRING,
*
PUNICODE_STRING;


typedef
struct
_LDR_MODULE
...
{
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
}
LDR_MODULE,
*
PLDR_MODULE;


typedef
struct
RTL_DRIVE_LETTER_CURDIR

...
{
USHORT Flags;
USHORT Length;
ULONG TimeStamp;
UNICODE_STRING DosPath;
}
RTL_DRIVE_LETTER_CURDIR,
*
PRTL_DRIVE_LETTER_CURDIR;

typedef
struct
_RTL_USER_PROCESS_PARAMETERS

...
{
ULONG AllocationSize;
ULONG Size;
ULONG Flags;
ULONG DebugFlags;
HANDLE hConsole;
ULONG ProcessGroup;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
UNICODE_STRING CurrentDirectoryName;
HANDLE CurrentDirectoryHandle;
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
PWSTR Environment;
ULONG dwX;
ULONG dwY;
ULONG dwXSize;
ULONG dwYSize;
ULONG dwXCountChars;
ULONG dwYCountChars;
ULONG dwFillAttribute;
ULONG dwFlags;
ULONG wShowWindow;
UNICODE_STRING WindowTitle;
UNICODE_STRING Desktop;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeInfo;
RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
}
RTL_USER_PROCESS_PARAMETERS,
*
PRTL_USER_PROCESS_PARAMETERS;

typedef VOID (_stdcall
*
PPEBLOCKROUTINE)(PVOID);

typedef
struct
_PEB_FREE_BLOCK

...
{
struct _PEB_FREE_BLOCK* Next;
ULONG Size;
}
PEB_FREE_BLOCK,
*
PPEB_FREE_BLOCK;

struct
_NT_PEB

...
{
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
BOOLEAN Spare;
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA LoaderData;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PVOID FastPebLock;
PPEBLOCKROUTINE FastPebLockRoutine;
PPEBLOCKROUTINE FastPebUnlockRoutine;
ULONG EnvironmentUpdateCount;
PVOID *KernelCallbackTable;
PVOID EventLogSection;
PVOID EventLog;
PPEB_FREE_BLOCK FreeList;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[0x2];
PVOID ReadOnlySharedMemoryBase;
PVOID ReadOnlySharedMemoryHeap;
PVOID *ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
BYTE Spare2[0x4];
LARGE_INTEGER CriticalSectionTimeout;
ULONG HeapSegmentReserve;
ULONG HeapSegmentCommit;
ULONG HeapDeCommitTotalFreeThreshold;
ULONG HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PVOID **ProcessHeaps;
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
PVOID GdiDCAttributeList;
PVOID LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
ULONG OSBuildNumber;
ULONG OSPlatformId;
ULONG ImageSubSystem;
ULONG ImageSubSystemMajorVersion;
ULONG ImageSubSystemMinorVersion;
ULONG GdiHandleBuffer[0x22];
ULONG PostProcessInitRoutine;
ULONG TlsExpansionBitmap;
BYTE TlsExpansionBitmapBits[0x80];
ULONG SessionId;
}
;

typedef
struct
_CLIENT_ID

...
{
HANDLE UniqueProcess;
HANDLE UniqueThread;
}
CLIENT_ID,
*
PCLIENT_ID;

typedef
struct
_GDI_TEB_BATCH

...
{
ULONG Offset;
ULONG HDC;
ULONG Buffer[0x136];
}
GDI_TEB_BATCH,
*
PGDI_TEB_BATCH;

struct
_NT_TEB

...
{

NT_TIB Tib; /**//* 00h */

PVOID EnvironmentPointer; /**//* 1Ch */

CLIENT_ID Cid; /**//* 20h */

PVOID ActiveRpcInfo; /**//* 28h */

PVOID ThreadLocalStoragePointer; /**//* 2Ch */

_NT_PEB *Peb; /**//* 30h */

ULONG LastErrorValue; /**//* 34h */

ULONG CountOfOwnedCriticalSections; /**//* 38h */

PVOID CsrClientThread; /**//* 3Ch */

void* Win32ThreadInfo; /**//* 40h */

ULONG Win32ClientInfo[0x1F]; /**//* 44h */

PVOID WOW32Reserved; /**//* C0h */

LCID CurrentLocale; /**//* C4h */

ULONG FpSoftwareStatusRegister; /**//* C8h */

PVOID SystemReserved1[0x36]; /**//* CCh */

PVOID Spare1; /**//* 1A4h */

LONG ExceptionCode; /**//* 1A8h */

UCHAR SpareBytes1[0x28]; /**//* 1ACh */

PVOID SystemReserved2[0xA]; /**//* 1D4h */

GDI_TEB_BATCH GdiTebBatch; /**//* 1FCh */

ULONG gdiRgn; /**//* 6DCh */

ULONG gdiPen; /**//* 6E0h */

ULONG gdiBrush; /**//* 6E4h */

CLIENT_ID RealClientId; /**//* 6E8h */

PVOID GdiCachedProcessHandle; /**//* 6F0h */

ULONG GdiClientPID; /**//* 6F4h */

ULONG GdiClientTID; /**//* 6F8h */

PVOID GdiThreadLocaleInfo; /**//* 6FCh */

PVOID UserReserved[5]; /**//* 700h */

PVOID glDispatchTable[0x118]; /**//* 714h */

ULONG glReserved1[0x1A]; /**//* B74h */

PVOID glReserved2; /**//* BDCh */

PVOID glSectionInfo; /**//* BE0h */

PVOID glSection; /**//* BE4h */

PVOID glTable; /**//* BE8h */

PVOID glCurrentRC; /**//* BECh */

PVOID glContext; /**//* BF0h */

LONG LastStatusValue; /**//* BF4h */

UNICODE_STRING StaticUnicodeString; /**//* BF8h */

WCHAR StaticUnicodeBuffer[0x105]; /**//* C00h */

PVOID DeallocationStack; /**//* E0Ch */

PVOID TlsSlots[0x40]; /**//* E10h */

LIST_ENTRY TlsLinks; /**//* F10h */

PVOID Vdm; /**//* F18h */

PVOID ReservedForNtRpc; /**//* F1Ch */

PVOID DbgSsReserved[0x2]; /**//* F20h */

ULONG HardErrorDisabled; /**//* F28h */

PVOID Instrumentation[0x10]; /**//* F2Ch */

PVOID WinSockData; /**//* F6Ch */

ULONG GdiBatchCount; /**//* F70h */

USHORT Spare2; /**//* F74h */

BOOLEAN IsFiber; /**//* F76h */

UCHAR Spare3; /**//* F77h */

ULONG Spare4; /**//* F78h */

ULONG Spare5; /**//* F7Ch */

PVOID ReservedForOle; /**//* F80h */

ULONG WaitingOnLoaderLock; /**//* F84h */

ULONG Unknown[11]; /**//* F88h */

PVOID FlsSlots; /**//* FB4h */

PVOID WineDebugInfo; /**//* Needed for WINE DLL's */
}
;

static
struct
_NT_TEB
*
GetCurrentThreadTEB()
//
获得TEB

...
{
struct _NT_TEB *pTeb=NULL;

_asm

...{
mov eax,fs:[0x18]
mov pTeb,eax
}
return pTeb;
}

void
HideModule(std::
string
strModuleName)

...
{
struct _NT_TEB *pTeb = GetCurrentThreadTEB();
struct _NT_PEB *pPeb = pTeb->Peb; //由TEB获得PEB
PPEB_LDR_DATA pLdrData = pPeb->LoaderData;
PLDR_MODULE pFirstLdrModule = (PLDR_MODULE)pLdrData->InLoadOrderModuleList.Flink;
PLDR_MODULE pLdrModule = pFirstLdrModule;
PLDR_MODULE pLastModule,pNextModule;

//名字通通转为WideChar,因此Windows内部是Unicode的

WCHAR pWStrModuleName[MAX_PATH] = ...{WCHAR(0)};
MultiByteToWideChar(CP_ACP,0,strModuleName.c_str(), -1,pWStrModuleName,strModuleName.size());

//PEB里面有当前进程的模块列表,ToolHelp里面的函数就是根据这个列表来遍历的因此,修改此列表可以达到隐藏的目的
do

...{
//判断是否是我们要屏蔽的模块
if(wcscmp(pLdrModule->BaseDllName.Buffer, pWStrModuleName) == 0)

...{
//更改指针,达到隐藏的目的
pLastModule = (PLDR_MODULE)(pLdrModule->InLoadOrderModuleList.Blink);
pNextModule = (PLDR_MODULE)(pLdrModule->InLoadOrderModuleList.Flink);
pLastModule->InLoadOrderModuleList.Flink = (PLIST_ENTRY)pNextModule;
pNextModule->InLoadOrderModuleList.Blink = (PLIST_ENTRY)pLastModule;

//因为PEB里面有三个列表(分别是以Load顺序、地址顺序、初始化顺序来排序),所以通过覆盖的方式修改另外两个列表,达到隐藏的目的
pLdrModule->BaseAddress = pLastModule->BaseAddress;
pLdrModule->BaseDllName = pLastModule->BaseDllName;
pLdrModule->EntryPoint = pLastModule->EntryPoint;
pLdrModule->Flags = pLastModule->Flags;
pLdrModule->FullDllName = pLastModule->FullDllName;
pLdrModule->HashTableEntry = pLastModule->HashTableEntry;
pLdrModule->LoadCount = pLastModule->LoadCount;
pLdrModule->SizeOfImage = pLastModule->SizeOfImage;
pLdrModule->TimeDateStamp = pLastModule->TimeDateStamp;
pLdrModule->TlsIndex = pLastModule->TlsIndex;
}
pLdrModule = (PLDR_MODULE)pLdrModule->InLoadOrderModuleList.Flink;

} while(pLdrModule != pFirstLdrModule);
}
2.手动完成dll的加载:刚开始研究手动加载的时候觉得比较复杂,但是通过实践之后,其实还是很简单的,代码比较长这里就不详加叙述了,我就用下面几个步骤来分别叙述:
- 首先要分配一个空间给dll,可以根据PE结构里面的SizeOfImage来分配;
- 然后把dll加载到分配的空间里面去,需要注意的是不能单纯拷贝,对于每个Section而言,需要安排到Section列表里面指定的虚拟地址偏移里面去(即RAV + 分配到的空间开始地址<可以称为模块句柄>);
- 然后要做的就是完成IAT的填写(根据INT)以及重定位表的处理
- ok,打完收工(还有些比较复杂的处理我还不太明白,比如TLS,努力学习中)
因为手动加载dll没有经过系统的干涉,所以上面的PEB结构里面也就不会有相应的模块结构,也就达到了隐藏的目的。