|
[原创]利用堆栈回溯来编写驱动防火墙
BOOL load_sysfile( IN WCHAR* szPath ) { PEPROCESS proc = NULL ; BOOL bSuccess = FALSE ; NTSTATUS status = STATUS_SUCCESS ; SYSTEM_LOAD_AND_CALL_IMAGE GregsImage ; if ( NULL == szPath ) { return 0 ; } // 2次调用,得到csrss.exe的EPROCESS status = GetEProcessByName_QueryInfo( L"CSRSS.EXE", &proc ); if( !NT_SUCCESS(status) ) { status = GetEProcessByName_QueryInfo( L"csrss.exe", &proc ); if( !NT_SUCCESS(status) ) return 0 ; } GregsImage.ModuleName.Buffer = ExAllocatePoolWithTag(0, 100, ' kdD'); if ( NULL == GregsImage.ModuleName.Buffer ) { dprintf( "load_sysfile() ExAllocatePool() Failed\n" ) ; return 0 ; } wcscpy( GregsImage.ModuleName.Buffer, szPath); GregsImage.ModuleName.Length = 2 * wcslen( szPath ); GregsImage.ModuleName.MaximumLength = 100 ; // RtlInitUnicodeString( &(GregsImage.ModuleName), szPath ); KeAttachProcess (proc); // 附着到此进程 status = ZwSetSystemInformation( SystemLoadAndCallImage, &GregsImage, sizeof(SYSTEM_LOAD_AND_CALL_IMAGE) ) ; KeDetachProcess(); // Detach if( !NT_SUCCESS( status ) ) { dprintf( "load_sysfile() Failed: 0x%08lx\n", status ) ; ExFreePool( GregsImage.ModuleName.Buffer); return 0 ; } ExFreePool( GregsImage.ModuleName.Buffer); dprintf( "load_sysfile() ,OK!!!\n" ) ; return 1 ; } |
|
[原创]利用堆栈回溯来编写驱动防火墙
VOID fake_KeWaitForSingleObject ( ) /*++ Author: sudami [sudami@163.com] Time : 2008/12/23 [23:12:2008 - 7:16] Routine Description: 栈回溯获取MmLoadSystemImage的地址 win2k下的调用链如下: NtSetSystemInformation->MmLoadSystemImage->MiLoadSystemImage->KeWaitForSingleObject XP以后没有中间那个>MiLoadSystemImage了.在WIN2K里要多回溯一次 --*/ { PULONG PEBP ; UCHAR *pOpcode; __asm { pushfd pushad } g_bIsW2k = g_hardOffset.bIsW2k ; if ( g_tmpThread_for_KeWaitForSingleObject != (ULONG)KeGetCurrentThread() ) { goto _over_for_KeWaitForSingleObject ; } __asm { // int 3 mov PEBP, ebp mov ebx, PEBP mov ebx, [ebx] ; 回溯1次到 call MmLoadSystemImage 空间 cmp g_bIsW2k, 1 jnz _xp_ mov ebx, [ebx] ; WIN2K 要多回溯一次 _xp_: mov ebx, [ebx+4] ; ebp+4 --> ret Addr sub ebx, 5 ; ret-5 --> 由ret Addr到Call MmLoadSystemImage mov edi, ebx ; edi 保存Call MmLoadSystemImage处的地址 /*++ ChildEBP RetAddr Args to Child f9df7804 805a370b 80554440 00000012 00000000 VirusAnalyse!fake_KeWaitForSingleObject+0x1f f9df79b0 80605cb2 f9df7b38 00000000 00000000 nt!MmLoadSystemImage+0x1a9 <-- 触发成功 f9df7b60 8053da28 00000026 f9df7bf8 00000008 nt!NtSetSystemInformation+0x37c<-- 到达内核态Nt* f9df7b60 804ff711 00000026 f9df7bf8 00000008 nt!KiFastCallEntry+0xf8 <-- 经过中转站 f9df7be4 f9ca5053 00000026 f9df7bf8 00000008 nt!ZwSetSystemInformation+0x11 f9df7c0c f9ca4d0d f9df7c2c 816f5cf8 e13b815a VirusAnalyse!load_sysfile+0xc3 <-- 我们来触发它 f9df7c50 6f526d65 535c746f 65747379 5c32336d VirusAnalyse!Get_MmLoadSystemImage_addr+0x16d nt!NtSetSystemInformation+0x365: 80605ca5 6a01 push 1 80605ca7 57 push edi 80605ca8 57 push edi 80605ca9 8d45d8 lea eax,[ebp-28h] 80605cac 50 push eax ; 我们关心的参数,里面包含加载模块的全路径 80605cad e8b0d8f9ff call nt!MmLoadSystemImage (805a3562) <-- 回溯到这里 80605cb2 8945e4 mov dword ptr [ebp-1Ch],eax 80605cb5 3bc7 cmp eax,edi 80605cb7 0f8cb0040000 jl nt!NtSetSystemInformation+0x837 (8060616d) 80605cbd ff75ac push dword ptr [ebp-54h] 80605cc0 e82b52f2ff call nt!RtlImageNtHeader (8052aef0) <-- 校验 80605cc5 898568ffffff mov dword ptr [ebp-98h],eax 80605ccb 3bc7 cmp eax,edi 80605ccd 7512 jne nt!NtSetSystemInformation+0x3ab (80605ce1) 80605ccf ff75b4 push dword ptr [ebp-4Ch] 80605cd2 e8efd2f9ff call nt!MmUnloadSystemImage (805a2fc6)<-- 顺便可以把它的地址找到 80605cd7 b87b0000c0 mov eax,0C000007Bh 80605cdc e98c040000 jmp nt!NtSetSystemInformation+0x837 (8060616d) --*/ cmp g_ntoskrnl_addr, 0 jz _Skip2Check_ cmp g_ntoskrnl_size, 0 jz _Skip2Check_ mov ecx, g_ntoskrnl_addr cmp ebx, ecx jbe short _over_for_KeWaitForSingleObject mov edx, g_ntoskrnl_size lea esi, [edx+ecx] cmp ebx, esi jnb short _over_for_KeWaitForSingleObject lea edx, [ebx+30h] cmp edx, ecx jbe short _over_for_KeWaitForSingleObject cmp edx, esi jnb short _over_for_KeWaitForSingleObject _Skip2Check_: // 是在内核地址范围内,进一步验证 add ebx, 5 ; 到达 call nt!MmLoadSystemImage 的下一条指令 xor ecx, ecx ; ecx == 每次调用SizeOfCode得到的指令长度 _loop_: ; 以ebx为起始地址, 往下30h字节内搜索第一个CALL,进行校验 // cmp BYTE ptr [ecx+ebx], 0E8h // 这样找太危险了.刚好碰到一种情况,数据是E8,而不是指令 // 从而导致地址不可读,BSOD了.这里还是应该带一个反汇编引擎 push ecx ; -->保存ecx mov pOpcode, 0 lea edx, pOpcode ; UCHAR *pOpcode; [OUT] 指令内容 lea ecx, [ecx+ebx] ; UCHAR *cPtr ; [IN] 当前指令地址 call SizeOfCode ; Length = SizeOfCode(cPtr, &pOpcode); // fastcall类型 // 此时ecx的值变成0了.故之前需要保存下 pop ecx ; -->恢复ecx add ecx, eax ; ecx += Length cmp eax,0 jnz __dddd__ inc ecx ; 若反汇编引擎计算的长度为0,则地址也要往后累加 jmp _next_ __dddd__: mov esi, [pOpcode] ; esi得到当前指令的地址 cmp BYTE ptr [esi], 0E8h ; 是否为CALL指令 jnz short _next_ /*++ 传进来的地址明明是正确的,但一调用MmIsAddressValid就崩,很奇怪很奇怪~~ STACK_TEXT: WARNING: Frame IP not in any known module. Following frames may be wrong. f9defc54 535c746f 65747379 5c32336d 726b746e 0x6f526d65 f9defc7c 805767dc 815d8b10 814b7000 00000000 0x535c746f <-- 明显是EIP执行到了非法地址 f9defd4c 805768eb 000000a8 00000001 00000000 nt!IopLoadDriver+0x66c f9defd74 80534fe6 000000a8 00000000 817bbda8 nt!IopLoadUnloadDriver+0x45 f9defdac 805c5cce f7fe2cf4 00000000 00000000 nt!ExpWorkerThread+0x100 f9defddc 805421c2 80534ee6 00000001 00000000 nt!PspSystemThreadStartup+0x34 00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16 // push esi ; esi == call RtlImageNtHeader 处的地址 // call MmIsAddressValid // cmp eax, 0 // jz _next_ // // lea edx, [esi+1] // push edx // call MmIsAddressValid // cmp eax, 0 // jz _next_ --*/ lea edx, [esi+1] ; esi == call RtlImageNtHeader 处的地址 mov eax, [edx] ; eax == offset lea eax, [esi+eax+5] cmp eax, g_RtlImageNtHeader_addr jz _ok_ _next_: cmp ecx, 30h jb short _loop_ jmp _over_for_KeWaitForSingleObject _ok_: lea ecx, [edi+1] ; edi 保存Call MmLoadSystemImage处的地址 mov edx, [ecx] lea eax, [edx+edi+5] mov g_MmLoadSystemImage_addr, eax ; OK! Well Done. _over_for_KeWaitForSingleObject: popad // VOID 类型的申明,非naked.所以编译器会自动生成一些垃圾代码 popfd // 这里的pop是为了平衡堆栈.必须的 pop edi pop esi pop ebx // pop ecx // 若只有一个局部变量,编译器可能会:push ecx,而不是sub esp,4 // 故调用wy的引擎,在fake函数中若用到局部变量,最好>=2 counts add esp, 8 // 清掉局部变量 _emit 0x5D // pop ebp _emit 0x68 // push xxxx _emit 0x00 _emit 0x00 _emit 0x00 _emit 0x00 ret } } |
|
[原创]利用堆栈回溯来编写驱动防火墙
引用: 但是通过我跟踪堆栈调用,发现要经过很多次KeWaitForSingleObject调用,才会进入 因为楼主没有主动触发,所以要多次.以下代码是主动触发,马上就能定位了啊 VOID Get_MmLoadSystemImage_addr( ) /*++ Author: sudami [sudami@163.com] Time : 2008/12/23 [23:12:2008 - 10:23] Routine Description: 获取MmLoadSystemImage的地址 --*/ { NTSTATUS status ; UNICODE_STRING uFileName; STRING ntNameString; CCHAR ntNameFile[128] = "\\??\\C:\\"; // 得到 KeWaitForSingleObject 原始地址 g_KeWaitForSingleObject_dwAddr = GetExportFuncOrigAddr( "KeWaitForSingleObject", FALSE ) ; dprintf( "KeWaitForSingleObject:0x%08lX \n", g_KeWaitForSingleObject_dwAddr ) ; if ( 0 == g_KeWaitForSingleObject_dwAddr ) { g_KeWaitForSingleObject_dwAddr = (ULONG) GetNativeFunctionBaseAddress( L"KeWaitForSingleObject" ) ; } // 得到 RtlImageNtHeader 原始地址 g_RtlImageNtHeader_addr = GetExportFuncOrigAddr( "RtlImageNtHeader", FALSE ) ; dprintf( "RtlImageNtHeader:0x%08lX \n", g_RtlImageNtHeader_addr ) ; if ( 0 == g_RtlImageNtHeader_addr ) { g_RtlImageNtHeader_addr = (ULONG) GetNativeFunctionBaseAddress( L"RtlImageNtHeader" ) ; } // 今天才发现,不需要释放任何驱动,随便给ZwSetSystemInformation乱传一个路径,都会进入到 // MmLoadSystemImage函数中,这就够了 by sudami 26-12-2008 // GenerateRandomStrings(5) ; // 产生随机名 // if ( NULL != szTmpName ) // { // sprintf( ntNameFile+strlen(ntNameFile), "%s.sys", szTmpName ); // RtlInitAnsiString( &ntNameString, ntNameFile); // RtlAnsiStringToUnicodeString( &uFileName, &ntNameString, TRUE ); // // // 释放测试驱动到C盘根目录 // status = PutFile( uFileName.Buffer, Test_sys_data, sizeof(Test_sys_data) ) ; // // RtlFreeUnicodeString(&uFileName); // // } else { // sprintf( ntNameFile+strlen(ntNameFile), "%s.sys", szTmpName ); // RtlInitAnsiString( &ntNameString, ntNameFile); // RtlAnsiStringToUnicodeString( &uFileName, &ntNameString, TRUE ); // // wcscpy( g_wszName, uFileName.Buffer ) ; // // RtlFreeUnicodeString(&uFileName); // // status = PutFile( g_wszName, Test_sys_data, sizeof(Test_sys_data) ) ; // } // // if ( STATUS_SUCCESS != status ) // { // dprintf( "PutFile(), Failed!\n" ) ; // return ; // } /*++ 先瞬间Inline Hook掉KeWaitForSingleObject,再迅速调用ZwSetSystemInformation加载释放到C盘 根目录的测试驱动.这样会马上执行到钩子里,在此进行栈回溯,最终定位到NtSetSystemInformation 函数调用MmLoadSystemImage的地方. 得到MmLoadSystemImage的地址. by sudami --*/ g_ntoskrnl_addr = g_ntoskrnl_info.ntoskrnl_addr ; g_ntoskrnl_size = g_ntoskrnl_info.ntoskrnl_size ; if ( !MmIsAddressValid( (PVOID)g_KeWaitForSingleObject_dwAddr ) || g_KeWaitForSingleObject_dwAddr < g_ntoskrnl_addr ) { dprintf( "g_KeWaitForSingleObject_dwAddr, INVALID,Failed!\n" ) ; return ; } if( !HookCode95( (PVOID)g_KeWaitForSingleObject_dwAddr, (PVOID)fake_KeWaitForSingleObject, InlineHookPre1) ) { // 前5字节JMP. dprintf( "HOOK KeWaitForSingleObject, Failed!\n" ) ; return ; } g_tmpThread_for_KeWaitForSingleObject = (ULONG)KeGetCurrentThread(); load_sysfile( g_wszName ) ; g_tmpThread_for_KeWaitForSingleObject = 0 ; UnhookCode95( fake_KeWaitForSingleObject ) ; } |
|
[原创]初步逆向,未发现QQ扫描隐私文件
就你这点烂技术,还注意场合? 笑死. |
|
[原创]内核驱动文件重定向 加图加代码
楼猪试试在R3做文件虚拟化~ |
|
[题目][第一阶段 第三题]『深圳腾讯2010安全技术竞赛』
为什么这3题我一题都不会,这叫人怎么玩儿... |
操作理由
RANk
{{ user_info.golds == '' ? 0 : user_info.golds }}
雪币
{{ experience }}
课程经验
{{ score }}
学习收益
{{study_duration_fmt}}
学习时长
基本信息
荣誉称号:
{{ honorary_title }}
能力排名:
No.{{ rank_num }}
等 级:
LV{{ rank_lv-100 }}
活跃值:
在线值:
浏览人数:{{ visits }}
最近活跃:{{ last_active_time }}
注册时间:{{ user_info.create_date_jsonfmt }}
勋章
兑换勋章
证书
证书查询 >
能力值