RCE Messageboard's Regroupment   Woodmann.com Swag Woodmann.com Swag Woodmann.com Swag

Go Back   RCE Messageboard's Regroupment > Blogs


To keep track of the posts in all our local blogs, subscribe to this RSS feed

To keep track of new threads (in all forums) of the RCE Messageboard, subscribe to this RSS feed

To keep track of all updates to the Collaborative RCE Tool Library, subscribe to this RSS feed

To get your own (reversing related) blog here, simply login and then click "Post to my Blog" below!


Old

VMware ring3 detection (RF handling)

Posted 08-09-2009 at 11:28 AM by deroko

Hello,

Here is one trick to detect vmware discovered by accidance

I was writing one unpacker, and for me RF was must have to make my unpacker simpler. Unpacker worked great on live system, and then I tried it in vmware, and I got many breaks at same part of the code which should be continued with RF.

RF from intel manual volume 3, chapter 18:

Code:
Because the debug exception for an instruction breakpoint is generated before the
instruction is executed, if the instruction breakpoint is not removed by the exception
handler; the processor will detect the instruction breakpoint again when the instruction
is restarted and generate another debug exception. To prevent looping on an
instruction breakpoint, the Intel 64 and IA-32 architectures provide the RF flag
(resume flag) in the EFLAGS register (see Section 2.3, “System Flags and Fields in
the EFLAGS Register,” in the Intel® 64 and IA-32 Architectures Software Developer’s
Manual, Volume 3A). When the RF flag is set, the processor ignores instruction
breakpoints.
Basically waht debugger would do with break point is:
- breakpoint reached -> clear breakpoint
- single step that instruction
- set breakpoint after singlestep
- continue execution
- too much not needed work...

For DebugRegister breaks on execution, you can simplfy this by setting RF in Eflags, and you don't have to remove your breakpoint on execution.

So here is how to detect VMWare presence using debug registers due to wrong RF handling:

Code allocates memory and stores there 0xC3, after that program generates exception to set debug registers. In exception handler code checks if exception occured 1st time (1st debug break) and sets RF (eg. continue execution), after that if exception occurs 2nd time, means that RF wasn't handled and that we have vmware (didn't try with other virtual machines).

main.c
Code:
#include        "defs.h"

PVOID   buffer;
DWORD   dwExceptionCount;

ULONG   filter(PEXCEPTION_INFO pei){
        PCONTEXT pctx;
        
        pctx = pei->pContext;
        if (dwExceptionCount == 0){
                dwExceptionCount++;
                pctx->Dr7 = BPM_LOCAL_EXACT | BPM0_LOCAL_ENABLED;
                pctx->Dr0 = (DWORD)buffer;
                pctx->Eip += 2;
                NtContinue(pctx, FALSE);
        }else if (dwExceptionCount == 1){
                dwExceptionCount++;
                pctx->EFlags |= 0x10000;
                NtContinue(pctx, FALSE);
        }else if (dwExceptionCount == 2){
                printf("[X] vmware detected\n");
                ExitProcess(0);
        }
        
        return EXCEPTION_EXECUTE_HANDLER;        
}

void __declspec(naked) hook_filter(void){
        __asm push      esp
        __asm call      filter
}

int __cdecl wmain(int argc, wchar_t **argv){
        VOID    (*func)();
        DWORD   dwOldProt;
        PUCHAR  kiuser;
        printf("[*] ring3 VMWARE detection - (c) 2009 deroko of ARTeam\n");
        kiuser = (PUCHAR)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "KiUserExceptionDispatcher");
        
        VirtualProtect(kiuser, 7, PAGE_EXECUTE_READWRITE, &dwOldProt);
        kiuser[0] = 0x68;
        *(DWORD *)&kiuser[1] = (DWORD)hook_filter;
        kiuser[5] = 0xc3;
                    
        buffer = func = VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        *(DWORD *)func = 0xC3909090;
        
        __asm xor eax, eax
        __asm mov eax, [eax]
        func();
        
        printf("[*] vmware not detected\n");
        ExitProcess(0);
}

defs.h
Code:
 
#include        <windows.h>
#include        <stdio.h>

// Dr6
#define BPM0_DETECTED                    0x00000001
#define BPM1_DETECTED                    0x00000002
#define BPM2_DETECTED                    0x00000004
#define BPM3_DETECTED                    0x00000008

// Dr7
#define BPM0_LOCAL_ENABLED               0x00000001
#define BPM0_W                           0x00010000
#define BPM0_RW                          0x00030000

#define BPM1_LOCAL_ENABLED               0x00000004
#define BPM1_W                           0x00100000
#define BPM1_RW                          0x00300000

#define BPM2_LOCAL_ENABLED               0x00000010
#define BPM2_W                           0x01000000
#define BPM2_RW                          0x03000000

#define BPM3_LOCAL_ENABLED               0x00000040
#define BPM3_W                           0x10000000
#define BPM3_RW                          0x30000000

#define BPM_LOCAL_EXACT                  0x00000100

typedef LONG NTSTATUS;

NTSTATUS
NTAPI
NtContinue(__in PCONTEXT ctx, BOOL Alertalbe);

typedef struct{
	PULONG ExceptionCodeAddress;
	PCONTEXT   pContext;
	ULONG  ExceptionCode;
	ULONG  ExceptionFlags;
	PULONG ExceptionRecord;
	ULONG  ExceptionAddress;
	ULONG  NumberOfParameters;
	ULONG  ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
}EXCEPTION_INFO, *PEXCEPTION_INFO;

output of the program running in vmware:
Code:
[*] ring3 VMWARE detection - (c) 2009 deroko of ARTeam
[X] vmware detected
output of the program running on live system:

Code:
[*] ring3 VMWARE detection - (c) 2009 deroko of ARTeam
[*] vmware not detected

Hope you find it usefull
cr4zyserb
Posted in Uncategorized
Views 502 Comments 8 deroko is offline
Old

custom gpa spy

Posted 09-15-2008 at 12:56 PM by deroko

http://forums.accessroot.com/index.php?showtopic=7513

read above topic to know how this idea was born well actually this idea was in my mind for almost a two years, but never found it useful to fully develop working code, but after reading this topic, and comments at posted link, I've decided to give it a go status.

In short : at above link, you will find link to the other site which has statistic of used functions in common files. On other hand, many are missed due to GetProcAddress, and not to mention many being missed due to custom GetProcAddress. So how to spy custom GetProcAddress!?!? well read the code and you will see.

This could be useful for protection profiling, and there are some other ways which I would use to deal with this, but for now, it seems ok, just so you get the basic idea. code is really messy, as I hate writing ring3 debuggers...

full code and sample binary:
http://deroko.phearless.org/export_log.rar
cr4zyserb
Posted in Uncategorized
Views 1062 Comments 3 deroko is offline
Old

SoftICE and KDExtensions

Posted 08-13-2008 at 11:31 PM by deroko

Well I was writing one extension for softice, and I faced one serious problem which in turn might not be that big problem if softice authors decided to write softice code properly at some points. SoftICE manual doesn't provide us with concept how to write KDExtensions, but in turn it gives us tools which we might use to convert existing windbg extensions into softice extension. One of rules is that we may not use Exception Handling in KDExtension (taken from SoftICE manual), and silently it refuses usage of many exports from ntoskrnl.exe...

KD2SYS.exe works simply by adding extra code to your dll, and changing it's entrypoint to code which looks like this:

Code:
.1000147F: B800000000                     mov         eax,0
.10001484: C20800                         retn        8
.10001487: 0010                           add         [eax],dl
.10001489: 0000                           add         [eax],al
when extension is loaded, it MUST have Debug symbols so softice will know that it should check EntryPoint for mov eax, 0/retn 8 using INT 2D (during driver loading ntoskrnl.exe will call -> DbgLoadImageSymbols which in turns will call int 2D, hooked by SoftICE which will examine entrypoint of driver and substitute mov eax, 0 with jmp __softice_code which will in turn call DllEntryPoint.

Code:
PAGE:004D7D27                 push    dword ptr [edi] ; ImageBase
PAGE:004D7D29                 call    _CacheImageSymbols@4 ; CacheImageSymbols(x)   
PAGE:004D7D2E                 test    eax, eax
PAGE:004D7D30                 jz      __no_debug_symbols
Upper code shows part of ntos which checks if Debug directory is used, and after that it will call DbgLoadImageSymbols.


If you take a look at upper Disassm code, you may see that right after retn 08 is stored : 1000h which is RVA of DllEntryPoint... You may examine a little bit hook of int2D and you will see how loading of KD takes place in SoftICE, not a nuclear physics as you may trace Int2D hook in SoftICE without a problem, as it will be running at PASSIVE_LEVEL (level at which drivers are being loaded).

Next step is to create such driver that will have similar if not the same code which will be handld by SoftICE. My walkaround was to define DriverEntry in asm code like this:

Code:
extern                  DllEntryPoint@12:dword 
public  C               DriverEntry@8

DriverEntry@8:          mov     eax, 0
                        ret     8
                        dd      0FFFFFFFFh
                        dd      offset DllEntryPoint@12
Also make sure that TARGETTYPE=MINIPORT to link directly with DriverEntry@8 as your entrypoint, as DRIVER type will link using GsDriverEntry:

Code:
INIT:00011185                 public GsDriverEntry
INIT:00011185 GsDriverEntry   proc near
INIT:00011185                 mov     edi, edi
INIT:00011187                 push    ebp
INIT:00011188                 mov     ebp, esp
INIT:0001118A                 mov     eax, __security_cookie
INIT:0001118F                 test    eax, eax
...
INIT:000111B8                 mov     __security_cookie_complement, eax
INIT:000111BD                 pop     ebp
INIT:000111BE                 jmp     DriverEntry
Which is not what I want...

Next step is to write convert.c/asm code which will:

1. open your file
2. locate entry point
3. calculate relative offset of DllEntryPoint
4. store it in placess of 0FFFFFFFF
5. update checksum
6. save changes

Now you may have neet extension (at least that's how I write them). Kayaker probably has better solution

Now comes funn part which I figgured after making dump of whole memory in VMWare, as minidump wasn't enough for me.

I tried to call some procedures which require dropping of IRQL like ExAllocatePool, which will eventually endup in ExAcquireQueuedSpinLock, which will drop IRQL to DISPATCH_LEVEL. I've started receiving numerous BSODs, and I tought that IRQL was an issue... and those BSODs occured only, and only when I was breaking in softice from ring3 applications, so I figured something had to be wrong, but in my wildest dreams I wouldn't suspect that solution was that stupid...

Let's have a look at code responsible for calling KDExtension in softice:

Code:
.text:A7AB9D3A si_callExtension proc near             
.text:A7AB9D3A
.text:A7AB9D3A ExtensionApi    = dword ptr  8
.text:A7AB9D3A hCurrentProcess = dword ptr  0Ch
.text:A7AB9D3A hCurrentThread  = dword ptr  10h
.text:A7AB9D3A dwCurrentPc     = dword ptr  14h
.text:A7AB9D3A dwProcessor     = dword ptr  18h
.text:A7AB9D3A args            = dword ptr  1Ch
.text:A7AB9D3A
.text:A7AB9D3A                 push    ebp
.text:A7AB9D3B                 mov     ebp, esp
.text:A7AB9D3D                 push    ds
.text:A7AB9D3E                 push    es
.text:A7AB9D3F                 push    fs
.text:A7AB9D41                 push    gs
.text:A7AB9D43                 pusha
.text:A7AB9D44                 pushf
.text:A7AB9D45                 mov     edi, kd_extension_esp_start
.text:A7AB9D4B                 mov     ecx, kd_extension_stack_size
.text:A7AB9D51                 shr     ecx, 2
.text:A7AB9D54                 xor     eax, eax
.text:A7AB9D56                 cld
.text:A7AB9D57                 rep stosd
.text:A7AB9D59                 cli
.text:A7AB9D5A                 mov     save_sice_esp, esp
.text:A7AB9D60                 mov     save_sice_ebp, ebp
.text:A7AB9D66                 mov     ErrorString_to_display, 0
.text:A7AB9D70                 mov     si_extension_aborted_pagefault, 0
.text:A7AB9D77                 mov     b_extension_executing, 1
.text:A7AB9D7E                 mov     dl, 1
.text:A7AB9D80                 call    Install_Reinsall_DivideOverflowHandler
.text:A7AB9D85                 mov     esp, kd_extension_esp
.text:A7AB9D8B                 sti
.text:A7AB9D8C                 mov     fs, word ptr kd_extension_fs 
.text:A7AB9D92                 call    sub_A7AB9C86    
.text:A7AB9D97                 push    [ebp+args]
.text:A7AB9D9A                 push    [ebp+dwProcessor]
.text:A7AB9D9D                 push    [ebp+dwCurrentPc]
.text:A7AB9DA0                 push    [ebp+hCurrentThread]
.text:A7AB9DA3                 push    [ebp+hCurrentProcess]
.text:A7AB9DA6                 call    [ebp+ExtensionApi]
.text:A7AB9DA9 loc_A7AB9DA9:                           
.text:A7AB9DA9                 cli
.text:A7AB9DAA                 mov     esp, save_sice_esp
.text:A7AB9DB0                 mov     ebp, save_sice_ebp
.text:A7AB9DB6                 mov     b_extension_executing, 0
.text:A7AB9DBD                 call    restore_SEH
.text:A7AB9DC2                 xor     dl, dl
.text:A7AB9DC4                 call    Install_Reinsall_DivideOverflowHandler
.text:A7AB9DC9                 sti
.text:A7AB9DCA                 mov     edi, kd_extension_esp_start
.text:A7AB9DD0                 mov     ecx, kd_extension_stack_size
.text:A7AB9DD6                 shr     ecx, 2
.text:A7AB9DD9                 xor     eax, eax
.text:A7AB9DDB                 cld
.text:A7AB9DDC                 repe scasd
.text:A7AB9DDE                 mov     eax, ecx
.text:A7AB9DE0                 inc     eax
.text:A7AB9DE1                 shl     eax, 2
.text:A7AB9DE4                 popf
.text:A7AB9DE5                 popa
.text:A7AB9DE6                 pop     gs
.text:A7AB9DE8                 pop     fs
.text:A7AB9DEA                 pop     es
.text:A7AB9DEB                 pop     ds
.text:A7AB9DEC                 pop     ebp
.text:A7AB9DED                 retn    18h
.text:A7AB9DED si_callExtension endp
Now comes funny part, really funny part!!!!

Code:
.text:A7AB9D8C                 mov     fs, word ptr kd_extension_fs
This is not kd_extension_fs, this is FS of interupted TASK!!!!!!!!!! So if you are debugging ring3 code, KDExtension will be called with FS = 0x3B which points to TEB instead of KPCR, what most exports from ntoskrnl.exe will expect it to be!!! Of course, this is not the problem when you interupt TASK which is running in ring0, but I want my extension to work the same way no matter if interupted task is in ring0 or ring3.

That's the reason why KeSetEvent, ExAllocatePool, KeInsertQueueDpc and many, many others will fail, as those at some point expect FS to point to KPCR instead of TEB!

My solution was to create 2 functions, and call them, one at the beginning of exported function, and one at the end:

Code:
ULONG   old_fs;
void    set_fs()
{
        __asm{
                xor     eax, eax
                mov     ax, fs
                mov     old_fs, eax
                mov     eax, 30h
                mov     fs, ax
        }
}

void    restore_fs()
{
        __asm{
                mov     eax, old_fs
                mov     fs, ax
        }
}
Although those seem like not safe functions, remember that softice...
cr4zyserb
Posted in Uncategorized
Views 1000 Comments 2 deroko is offline
Old

SymbolFinder

Posted 07-19-2008 at 12:16 PM by deroko

Dunno if this is just me or this is for real, but if someone tries to google for some kind of example of symbol lister it will endup in dead-end (maybe I should work on my google skils ), anyway, I spent last 2 days playing and figuring these symbols (great MS simply points in MSDN to PDB documentation... where is that thing!??!!?), to write this enum, struct, symbol lister and decided to share my source so there can be at least one refference on how to list and parse symbols...

http://deroko.phearless.org/SymbolFinder.rar

Hope someone will find it usefull
cr4zyserb
Posted in Uncategorized
Views 1012 Comments 7 deroko is offline
Old

pde/pte softice plugin

Posted 07-08-2008 at 01:30 PM by deroko

Today I needed to verify some bits in PDE/PTE from SoftICE (well while I'm debugging) so I wrote one plugin for softice which will give me all needed information about pde/pte for a given address. Note that this is for PAE systems as I'm using PAE mainly... maybe I'll update it for non pae systems someday. Anyway, source is included

http://deroko.phearless.org/pdepte.rar
cr4zyserb
Posted in Uncategorized
Views 1169 Comments 0 deroko is offline
Old

build rule for x64 asm

Posted 06-22-2008 at 08:28 PM by deroko
Updated 06-22-2008 at 08:33 PM by deroko

I've made build rule for x64 asm files compiled from msvc2008. I had to use asm x64 in my C code. Hope it will be usefull
Code:
<?xml version="1.0" encoding="utf-8"?>
<VisualStudioToolFile
	Name="Masm64"
	Version="8.00"
	>
	<Rules>
		<CustomBuildRule
			Name="masm64"
			DisplayName="masm64"
			CommandLine="ml64.exe /c /nologo $(InputName).asm"
			Outputs=".\$(InputName).obj"
			FileExtensions="*.asm"
			ExecutionDescription="Assembling x64..."
			ShowOnlyRuleProperties="false"
			>
			<Properties>
			</Properties>
		</CustomBuildRule>
	</Rules>
</VisualStudioToolFile>
cr4zyserb
Posted in Uncategorized
Views 1017 Comments 0 deroko is offline
Old

nonintrusive tracer on x64

Posted 06-21-2008 at 10:44 AM by deroko

Well time has come to dig a little bit into x64 systems, and to move our lovely tools and ideas to that system.

Lets have a look at KiUserExceptionDispatcher from ntdll.dll:

Code:
.text:0000000077EF31B0                 public KiUserExceptionDispatcher
.text:0000000077EF31B0 KiUserExceptionDispatcher:              
.text:0000000077EF31B0                 mov     rax, cs:Wow64PrepareForException
.text:0000000077EF31B7                 test    rax, rax
.text:0000000077EF31BA                 jz      short loc_77EF31CB
.text:0000000077EF31BC                 mov     rcx, rsp
.text:0000000077EF31BF                 add     rcx, 4D0h
.text:0000000077EF31C6                 mov     rdx, rsp
.text:0000000077EF31C9                 call    rax ; Wow64PrepareForException
.text:0000000077EF31CB
.text:0000000077EF31CB loc_77EF31CB:                         
.text:0000000077EF31CB                 mov     rcx, rsp
.text:0000000077EF31CE                 add     rcx, 4D0h
.text:0000000077EF31D5                 mov     rdx, rsp
.text:0000000077EF31D8                 call    RtlDispatchException
.text:0000000077EF31DD                 test    al, al
.text:0000000077EF31DF                 jz      short loc_77EF31ED
.text:0000000077EF31E1                 mov     rcx, rsp
.text:0000000077EF31E4                 xor     edx, edx
.text:0000000077EF31E6                 call    RtlRestoreContext

Wow64PrepareForException is used only when loading wow64 process, so in "native x64" environment this variable is set to 0, and we can use that variable to write our own SEH handler in asm or nonintrusive tracer. Well let's cut to the point and see some real code:

Code:
                        mov     rax, KiUserExceptionDispatcher
                        xor     rbx, rbx
                        mov     ebx, dword ptr[rax+3]
                        add     rbx, rax
                        add     rbx, 7

                        mov     rax, offset __mykiuser
                        mov     [rbx], rax
                        
                        xor     rax, rax
                        mov     [rax], rax
                        
                        xor     r9, r9
                        mov     r8, offset szntdll
                        mov     rdx, offset szkiuser
                        mov     rcx, 0
                        callW   MessageBoxA
                        xor     rcx, rcx
                        callW   ExitProcess
                        
__mykiuser:             add     qword ptr[rdx+0F8h], 3
                        mov     rcx, rdx
                        xor     rdx, rdx
                        callW   RtlRestoreContext
If everything worked as planned, MessageBoxA will be shown... simple isn't it
cr4zyserb
Posted in Uncategorized
Views 954 Comments 1 deroko is offline
Old

IDA and vmread/vmwrite x64

Posted 05-20-2008 at 07:38 PM by deroko
Updated 05-20-2008 at 07:49 PM by deroko

These 2 instructions are defined as:

Code:
VMREAD  Ed/q, Gd/q
VMWRITE Gd/q, Ed/q
where d is for 32 bit environment, and q for 64 bit environment, which means that in 32 bit environment operands are always 32bit, and in 64bit environment those are 64bit, and operand size prefix can't affect size.

But IDA displays wrong info:

Code:
.text:0000000000011010                 mov     [rsp+arg_8], rdx
.text:0000000000011015                 mov     [rsp+arg_0], rcx
.text:000000000001101A                 sub     rsp, 38h
.text:000000000001101E                 mov     edx, 1
.text:0000000000011023                 mov     rcx, 1234567812345678h
.text:000000000001102D                 call    VmWrite_proc
.text:0000000000011032                 mov     rcx, 1234567812345678h
.text:000000000001103C                 call    VmRead_proc
.text:0000000000011041                 mov     [rsp+38h+var_18], rax
.text:0000000000011046                 xor     eax, eax
.text:0000000000011048                 add     rsp, 38h
.text:000000000001104C                 retn
.text:000000000001104C DriverEntry     endp

.text:0000000000011060 VmWrite_proc    proc near               
.text:0000000000011060                 vmwrite ecx, edx    <----- 32bit operands, which is not possible
.text:0000000000011063                 retn
.text:0000000000011063 VmWrite_proc    endp
.text:0000000000011063
.text:0000000000011064
.text:0000000000011064 VmRead_proc     proc near              
.text:0000000000011064                 vmread  eax, ecx    <----- again 32 bit operands
.text:0000000000011067                 retn
.text:0000000000011067 VmRead_proc     endp

Instead this should be displayed as vmwrite rcx, rdx and vmread rax, rcx. This is also verified by looking at intel documentation (CHAPTER 5 VMX INSTRUCTION REFERENCE - Volume 2B):

Code:
VMREAD—Read Field from Virtual-Machine Control Structure

Opcode Instruction Description
0F 78 VMREAD r/m64, r64 Reads a specified VMCS field (in 64-bit mode).
0F 78 VMREAD r/m32, r32 Reads a specified VMCS field (outside 64-bit mode).
and

Code:
VMWRITE—Write Field to Virtual-Machine Control Structure

Opcode Instruction Description
0F 79 VMWRITE r64, r/m64 Writes a specified VMCS field (in 64-bit mode)
0F 79 VMWRITE r32, r/m32 Writes a specified VMCS field (outside 64-bit mode)
Nothing spectacular, but still, wrong disassembly
cr4zyserb
Posted in Uncategorized
Views 1070 Comments 3 deroko is offline
Old

Intel VT and cpuid break

Posted 05-19-2008 at 09:33 PM by deroko

Do you want to use cpuid as int 3 or any other event? Well Intel VT allows us that, as cpuid always generates VM-Exit. In this case what we do is:

1. Read Guest Cr3 to check correct process
2. inject int 3 event into Guest
3. SoftICE will popup if i3here on is set
4. Enjoy

bin/src -> http://deroko.phearless.org/cpuid_break.rar
cr4zyserb
Posted in Uncategorized
Views 1096 Comments 8 deroko is offline
Old

dr7.gd on mp systems running sice

Posted 02-08-2008 at 11:47 AM by deroko

SoftICE uses drX to perform step over. One interesting question is how does it do that on MP system? It could happen that thread is running at one CPU, but code which is executed in certain procedure could switch to different CPU, and still SoftICE manages to stepover correctly. How is that possible? Using IPI, of course.

The best example is this code if steped over in SoftICE:

Code:
        KeSetAffinityThread(cur_thread, 1<<0);
        KeSetAffinityThread(cur_thread, 1<<1);
both calls will be steped over correctly, and that's because SoftICE sends IPI with Shorthand = All excluding self set in ICR to set drXes on both CPUs.

I also wrote earlier that softice changes NMI handler from TaskGate to IdtGate on single cpu machine, but when I viewed IDT on MP system from SoftICE, it used TaskGate to hook NMI. So there are certain rules which have to be followed when drX access occurs from NMI and TaskGate.

Handler must NOT iret if access to drX occurs from NMI, because iret will unblock NMI. Handler also must not use DbgPrint, or anything else that can trigger iret when executing from NMI...

Also if we are in NMI, SoftIce won't clear NT flag in eflags, so any iret will lead to previous task. We can avoid this problem by clearing NT flag, but again, we unblock NMI using iret, so this is sidenote, not a real problem.

This problem with iret is solved easily, by changing the way we return from int1 when it's caused from NMI:

Code:
   
__s0:           str     ax              ;get task register
                cmp     ax, 58h         ;check if it is NMI
                je      __nmi
                
                pop     es              ;not NMI so exit normally
                pop     ds
                pop     fs
                popad                                   
                iretd                                   
                                        
__nmi:          mov     eax, [esp.regEflags]            
                push    eax             ;NMI!! - restore eflags                
                popfd                                   
                pop     es              ;r0 epilog
                pop     ds
                pop     fs
                popad
                retn    8               ;ret to interupted code and
                                        ;clear cs/eflags stored on 
                                        ;stack...
Bingo... dr7.GD is now working in mp system running sice
cr4zyserb
Posted in Uncategorized
Views 1269 Comments 5 deroko is offline
Old

KeGetCurrentIrql can't return HIGH_LEVEL

Posted 02-03-2008 at 11:53 AM by deroko

I was playing with IRQL and spotted one interesting thing. If IRQL is raised to HIGH_LEVEL, then KeGetCurrentIrql will return wrong ifno about IRQL:

Code:
                                       
.text:800123B8 ; __fastcall KfRaiseIrql(x)
.text:800123B8                 public @KfRaiseIrql@4
.text:800123B8 @KfRaiseIrql@4  proc near     
.text:800123B8  
.text:800123B8                 movzx   edx, cl
.text:800123BB                 movzx   ecx, ds:_HalpIRQLtoTPR[edx]
.text:800123C2                 mov     eax, ds:0FFFE0080h
.text:800123C7                 mov     ds:0FFFE0080h, ecx
.text:800123CD                 shr     eax, 4
.text:800123D0                 movzx   eax, ds:_HalpVectorToIRQL[eax]
.text:800123D7                 retn
.text:800123D7 @KfRaiseIrql@4  endp
Decode IRQL to Task Priority Register [APIC_base+0x80]

Code:
.text:80012398 _HalpIRQLtoTPR  db   0h  <--- PASSIVE_LEVEL (0)
.text:80012399                 db  3Dh  <--- APC_LEVEL  (1)
.text:8001239A                 db  41h  <--- DISPATCH_LEVEL (2)
.text:8001239B                 db  41h  
.text:8001239C                 db  51h  
.text:8001239D                 db  61h  <--- CMCI_LEVEL (5)
.text:8001239E                 db  71h
.text:8001239F                 db  81h 
.text:800123A0                 db  91h
.text:800123A1                 db 0A1h
.text:800123A2                 db 0B1h 
.text:800123A3                 db 0B1h 
.text:800123A4                 db 0B1h 
.text:800123A5                 db 0B1h 
.text:800123A6                 db 0B1h
.text:800123A7                 db 0B1h 
.text:800123A8                 db 0B1h
.text:800123A9                 db 0B1h 
.text:800123AA                 db 0B1h
.text:800123AB                 db 0B1h 
.text:800123AC                 db 0B1h
.text:800123AD                 db 0B1h 
.text:800123AE                 db 0B1h
.text:800123AF                 db 0B1h 
.text:800123B0                 db 0B1h
.text:800123B1                 db 0B1h 
.text:800123B2                 db 0B1h
.text:800123B3                 db 0C1h  <--- PROFILE_LEVEL (27)
.text:800123B4                 db 0D1h  <--- CLOCK1/2_LEVEL (28)
.text:800123B5                 db 0E1h  <--- IPI_LEVEL  (29)
.text:800123B6                 db 0EFh  <--- POWER_LEVEL(30)
.text:800123B7                 db 0FFh  <--- HIGH_LEVEL (31)
Also there is a array used to decode Task Priority Register to IRQL:

Code:
.data:8001D218 _HalpVectorToIRQL db   0h        <--- PASSIVE_IRQL                                       
.data:8001D219                   db 0FFh
.data:8001D21A                   db 0FFh
.data:8001D21B                   db    1        <--- APC_LEVEL
.data:8001D21C                   db    2        <--- DISPATCH_LEVEL
.data:8001D21D                   db 0FFh
.data:8001D21E                   db 0FFh
.data:8001D21F                   db 0FFh
.data:8001D220                   db 0FFh
.data:8001D221                   db 0FFh
.data:8001D222                   db 0FFh
.data:8001D223                   db 0FFh
.data:8001D224                   db  1Bh        PROFILE_LEVEL
.data:8001D225                   db  1Ch        CLOCK1/2_LEVEL
.data:8001D226                   db  1Dh        IPI_LEVEL and POWER LEVEL
                                                are different in Task priority sub-class
                                                (lower 8bits of Task Priority Register)     
.data:8001D227                   db  1Eh        POWER_LEVEL
Basically if we are running at HIGH_LEVEL, KeGetCurrentIrql will always return POWER_LEVEL. Calculaion is simple here, it uses Task Priority, upper 8 bits of TPR (Task Priority Register) as index into _HalpVectorToIRQL or better name would be _HalpTPRtoIRQL for this 2nd array.

So are you sure that you are running at HIGH_IRQL? or POWER_LEVEL?
cr4zyserb
Posted in Uncategorized
Views 1236 Comments 6 deroko is offline
Old

softice nmi hook

Posted 01-26-2008 at 07:46 PM by deroko

NMI (int 0x02) is by default setup as TaskGate, which means that it points to TSS Descriptor where is stored TSS needed to transfer execution to r0 when NMI occurs.

sice not running:

Code:
00000002	0.00003269	TaskGate: 02 [58:00000000] DPL=0 P	
00000003	0.00004917	 + TSS at 80872568 - cs:eip = [08:8086698C]
sice running:
Code:
00000002	0.00004665	IdtGate : 02 [08:B45AE617] DPL=0 P
No practical rce use, but still funny thing
cr4zyserb
Posted in Uncategorized
Views 1131 Comments 4 deroko is offline
Old

dr7.gd - dr6 saving

Posted 01-03-2008 at 10:53 AM by deroko

Recenly I wrote a lille driver to test this feature with my softice, I didn't need it realy, but who know when it will become usefull.

Whole concept consist of setting dr7.GD to 1, and waiting for mov drX/reg or mov reg/drX to occur. Here is a little quote from IA32 manual:

Quote:
GD (general detect enable) flag (bit 13)
Enables (when set) debug-register protection, which causes a debug exception
to be generated prior to any MOV instruction that accesses a debug register.
When such a condition is detected, the BD flag in debug status register DR6 is
set prior to generating the exception. This condition is provided to support incircuit
emulators. (When the emulator needs to access the debug registers,
emulator software can set the GD flag to prevent interference from the program
currently executing on the processor.) The processor clears the GD flag upon
entering to the debug exception handler, to allow the handler access to the
debug registers.
Basically what this means is that GD is cleared each time int 1 exception occurs. This is done in the way so handler can examine dr6 for BS (indicates single steping) or other flags like BT, BD and B0-B1. If GD wouldn't be cleared in dr7 on int1 exception then handler would fall into infinite loop trying to access dr6 no matter what caused int1 as GD would constantly cause int1 to be called. This simply tells us that we have to set dr7.GD everytime when int 1 is generated no matter if we handle exception or pass it lower in the chain. Neet

Now we come to dr6 issue when softice is active(well when mov reg,dr6 occurs, but without sice I have no idea why this would be usefull - syser maybe???), if we watch and log activity of softice when stepover occurs we may see this:


Code:
0xB43517FE : mov dr3, esi
dr updated : 0xBA642A93        <------ step over instruction
0xB4351801 : mov dr7, ebx
dr updated : 0x00FF07C0        <------ set dr7 and wait
0xBA328683 : mov eax, dr6
dr value moved : 0xFFFF0FF8    <------ dr6 properly updated :)
0xB42BE589 : mov eax, dr6
dr value moved : 0xFFFF0FF8
0xB42BE596 : mov dr6, eax
dr updated : 0xFFFF0FF0
Now you may see that dr6.B3 is set, but this is done because I save dr6, and update it properly. Well still it's a walkaround for saving as I don't know any other better way to save it. Now let's descibe this problem, and why and how it happens:

When we enter int 1h (dr3 was hit), dr6 will have value as shown above: 0xFFFF0FF8, as we don't handle this exception, we have to set dr7.GD again, and pass it to the lower handler. Lower handle in the chain will access dr6, and cause dr6 to look like this : 0xFFFF2FF0 (BD set). Now if we emulate mov reg, dr6 with value 0xFFFF0FF0 (we clear BD flag from dr6), handler will not know that actually dr3 was hit which will lead to unhandled exception in kernel mode:

Quote:
BugCheck 1000008E, {80000004, ba5e6c7b, b5cb0194, 0}


Followup: MachineOwner
---------

kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

KERNEL_MODE_EXCEPTION_NOT_HANDLED_M (1000008e)
This is a very common bugcheck. Usually the exception address pinpoints
the driver/function that caused the problem. Always note this address
as well as the link date of the driver/image that contains this address.
Some common problems are exception code 0x80000003. This means a hard
coded breakpoint or assertion was hit, but this system was booted
/NODEBUG. This is not supposed to happen as developers should never have
hardcoded breakpoints in retail code, but ...
If this happens, make sure a debugger gets connected, and the
system is booted /DEBUG. This will let us see why this breakpoint is
happening.
Arguments:
Arg1: 80000004, The exception code that was not handled
Arg2: ba5e6c7b, The address that the exception occurred at
Arg3: b5cb0194, Trap Frame
Arg4: 00000000
Now let's take a little look into IA32 manual to see what really happens (older one):

Quote:
Note that the contents of the DR6 register are never cleared by the processor. To avoid any
confusion in identifying debug exceptions, the debug handler should clear the register before
returning to the interrupted program or task.
but is this really a true? now if we take a look into newer one:

Quote:
Certain debug exceptions may clear bits 0-3. The remaining contents of the DR6
register are never cleared by the processor. To avoid confusion in identifying debug exceptions,
debug handlers should clear the register before returning to the interrupted
task.
We may see that certain debug exception may clear B0-B3 but they don't say which ones. Obviously BD debug exception is the one. So may walkaround was to follow certain logic, of int1 handler:

1. when int1 occurs I save dr6 always
2. when dr6 update occurs I save it (mov dr6, reg)
3. when I detect mov reg, dr6, I update dr6 with proper value which was saved.

Hope this will be usefull to someone Actually our friendly neighbour yates wrote similar code long time ago : http://www.woodmann.com/collaborative/tools/index.php/Category:Technical_PoC_Tools but it has this little flaw in it.

ps. I really like how ms describes unhandled_exception :

Quote:
This is not supposed to happen as developers should never have
hardcoded breakpoints in retail code, but ...
but ... shit happens

cr4zyserb
Posted in Uncategorized
Views 1283 Comments 4 deroko is offline
Old

MmGetSystemRoutineAddress : forwards on vista

Posted 12-31-2007 at 10:42 AM by deroko

Very frustrating when you figure that this export can't resolve forwarded APIs. Here is one example from Vista:

Code:
.edata:8002F485 ; Exported entry   1. ExAcquireFastMutex
.edata:8002F485                 public ExAcquireFastMutex
.edata:8002F485 ExAcquireFastMutex db 'ntoskrnl.ExiAcquireFastMutex',0
.edata:8002F4A2 aExreleasefastm db 'ExReleaseFastMutex',0
.edata:8002F4B5 ; Exported entry   2. ExReleaseFastMutex
.edata:8002F4B5                 public ExReleaseFastMutex
.edata:8002F4B5 ExReleaseFastMutex db 'ntoskrnl.ExiReleaseFastMutex',0
.edata:8002F4D2 aExtrytoacquire db 'ExTryToAcquireFastMutex',0
.edata:8002F4EA ; Exported entry   3. ExTryToAcquireFastMutex
.edata:8002F4EA                 public ExTryToAcquireFastMutex
.edata:8002F4EA ExTryToAcquireFastMutex db 'ntoskrnl.ExiTryToAcquireFastMutex',0
When you use MmGetSystemRoutineAddress it will return to you address of string. It won't resolve forwarded API properly.

The best way is to use own MmGetSystemRoutineAddress instead of the one provided by windows kernel...
cr4zyserb
Posted in Uncategorized
Views 1570 Comments 11 deroko is offline
Old

imports are easy to fix

Posted 10-23-2007 at 11:39 AM by deroko
Updated 10-23-2007 at 12:53 PM by deroko

Well I read post at openrce posted by blabberer in X-Code thread here at woodmann (http://www.woodmann.com/forum/showthread.php?t=10635) and saw interesting discussion between Rolf Rolles (waz up man ) and Kris Kaspersky debating which way of generic fixing is better. Kris votes for adding loader, but Rolf likes clean import to have good disasm in IDA. Infact I had this same problem a few months ago, it was easy to locate all APIs and add loader, who cares, app works, well it works and you don't have to analyse it as long as registration scheme is located in the wraper, but what if registration is located in program itself and you have to analyse it? It would be mess and boring task in IDA not seeing real APIs Basically that small discussion was inspiration to write this blog post

Look at this messy fixed import. It looks like, for example, armadillo shuffled IAT or maybe ActiveMARK v6.xx fixed IAT. But take a closer
look where are APIs located:

Code:
00BBC368 >7C80A447  kernel32.QueryPerformanceCounter
00BBC36C >7E450702  USER32.MessageBoxA

kernel32.QueryPerformanceCounter = BBC364
user32.MessageBoxA               = BBC368
You might wonder how did I get this to work? Using API loader? No!!!

What I have used here is 1API = 1 image import descriptor concept which I use to fix imports always. Basically this is how it works:

Code:
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            
        DWORD   OriginalFirstThunk;         
    };
    DWORD   TimeDateStamp;                  
    DWORD   ForwarderChain;                 
    DWORD   Name;
    DWORD   FirstThunk;                     
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
According to PE specification OriginalFirstThunk points to API names, but if it is 0 then FirstThunk is pointing to API names, also FirstThunk is used to know where to store API addresses.


So what we shall do to make this concept work?

1. Build OriginalFirstThunk such that it only points to one API name
2. place RVA in FirstThunk where we want API loaded
3. When import table is built simply walk firstthunk and set it to
specific value != 0 as windows loader will deny loading image if
address to which FirstThunk is pointing is 0. Weird?! I didn't find
anything in PE specification about this behaviour

Lets see some code snipets from this library which you may find in src of my GenericUnpacker and import engine at http://deroko.phearless.org

First we define some struct which will hold our imports:

Code:
import_struct           struct
        is_address      dd      ?               <--- RVA where we want API address to be
                                                     writen by windows loader
        is_dlllen       dd      ?               <--- len of dll name including terminating 0
        is_apilen       dd      ?               <--- len of API string including terminating 0
                                                     or 4 if API is imported by ordinal
        is_dllname      db      256     dup(0)  <--- dllname (ASCII)
        is_apiname      db      256     dup(0)  <--- API name or ordinal | 0x80000000
import_struct           ends
Now it's very simply to fix IAT:

By number of this structs we know how many IMAGE_IMPORT_DESCRIPTORs we will have, but
also tnhx to lengths stored in structs we can estimate size of newly built IAT including
APIs aswell.

OriginalFirstThunk will always point to API name or ordinal and also will take one more
DWORD for 0 to tell windows loader that there are no more APIs to be loaded.


EBX = memory used for IMAGE_IMPORT_DESCRIPTOR
EDI = pointer where we write dll, api names or ordinals and is calculated
as EBX + (number_of_import_structs + 1) * sizeof (IMAGE_IMPORT_DESCRIPTOR)

Code:
                        sub     edx, size import_struct
                        
__cycle_main_loop:      add     edx, size import_struct
                        cmp     [edx.is_address], 0
                        je      __done_building
                
                        ;copy dll name
                        mov     esi, edi
                        sub     esi, new_iat_mem
                        add     esi, iat_sec_rva
                        
                        mov     [ebx.id_name], esi 
                        lea     esi, [edx.is_dllname]
                        mov     ecx, [edx.is_dlllen]
                        rep     movsb
                        
                        ;write original first thunk
                        mov     esi, eax
                        sub     esi, new_iat_mem
                        add     esi, iat_sec_rva
                        
                        mov     [ebx.id_originalfirstthunk], esi
                        
                        mov     esi, dword ptr[edx.is_apiname]
                        test    esi, 80000000h
                        jz      __api_has_name
                        mov     [eax], esi
                        jmp     __firstthunk         

__api_has_name:
                        mov     esi, edi
                        sub     esi, new_iat_mem
                        add     esi, iat_sec_rva
                        mov     [eax], esi
             
                        lea     esi, [edx.is_apiname]
                        add     edi, 2
                        mov     ecx, [edx.is_apilen]
                        rep     movsb

__firstthunk:                        
                        mov     esi, [edx.is_address]
                        mov     [ebx.id_firstthunk], esi
                        
                        add     ebx, size import_directory
                        add     eax, 8
                        jmp     __cycle_main_loop
When this small loop is done, all we have to do is to walk all first_thunks and set them
to != 0 so win loader can actually load this import table.

With this concept you don't have to write sorting algos to get nice and clean IAT, who
cares where are APIs located. In my, aspr2.3 dumper for example, I scan original code
for APIs that are not stolen, then I go for stolen APIs and write them into array
and I don't care if I have something like this:

MessageBoxA
GetModuleHandleA
RegOpenKeyExA

etc...

After this is done, then I go for APIs located in poly oep, or other stolen procedures
which are located in markers. At this point IAT looks like nightmare and importrec nor
any other public known engine can fix this IAT... But 1API = 1IDD concept fixes this
without a problem!!!

Think about it when writing unpacker and protection developers think too when
you try to make "hard" IAT to stop importrec, you will lose one way or another
Remember that not many people are using it lately
cr4zyserb
Posted in Uncategorized
Views 1305 Comments 5 deroko is offline

Just in case...Please update your bookmarks to http://woodmann.cjb.net
Direct link : http://71.6.196.237/forum/

Some Useful Places
Fravia's Searchlores
Fravia's Original Reversing Site
Krobars Collection of tutorials
OllyStuph OllyDbg Resources
A complete searchable archive of the forum in .CHM format is available (updated Jan 3, 2009)
here (25.8 Mb zip)
Please do not ask for cracks, instead read this.

Started 10 May 1999

All times are GMT -5. The time now is 05:40 PM.


Powered by vBulletin® Version 3.8.2
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.