1. softice nmi hook

    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:

    00000002	0.00003269	TaskGate: 02 [58:00000000] DPL=0 P	
    00000003	0.00004917	 + TSS at 80872568 - cs:eip = [08:8086698C]
    sice running:
    00000002	0.00004665	IdtGate : 02 [08:B45AE617] DPL=0 P
    No practical rce use, but still funny thing
  2. - dr6 saving

    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:

    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:

    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:

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

    Followup: MachineOwner

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

    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
    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):

    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:

    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
    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 : but it has this little flaw in it.

    ps. I really like how ms describes unhandled_exception :

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

  3. MmGetSystemRoutineAddress : forwards on vista

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

    .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...
  4. imports are easy to fix

    Well I read post at openrce posted by blabberer in X-Code thread here at woodmann ( 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:

    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:

    typedef struct _IMAGE_IMPORT_DESCRIPTOR {
        union {
            DWORD   Characteristics;            
            DWORD   OriginalFirstThunk;         
        DWORD   TimeDateStamp;                  
        DWORD   ForwarderChain;                 
        DWORD   Name;
        DWORD   FirstThunk;                     
    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

    First we define some struct which will hold our imports:

    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)

                            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         
                            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
                            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:



    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

    Updated October 23rd, 2007 at 11:53 by deroko

  5. Виртуелно, виртуелно и машински

    VirtualMachines are really boring, the real art of unpacking is changed with pointless vm reversing. It's really pointless as same result are achived with appending vm, but some authors really crack me up:

    (88) mov vm_reg298, 11B0A5B4h
    (39) add vm_reg298, 00000060h
    (97) mov vm_reg298, [vm_reg298]
    (DB) mov vm_reg244, 01101640
    (64) add vm_reg244, vm_reg298
    (6C) mov vm_regDC, 01107414h
    (64) add vm_regDC, vm_reg298
    (97) mov vm_regDC, [vm_regDC]
    (85) mov vm_reg1A4, vm_reg1C
    (26) add vm_reg244, 000000C4h
    (97) mov vm_reg2FC, [vm_reg244]
    (C3) add vm_reg2FC, vm_regDC
    (25) add vm_reg1A4, vm_reg2FC
    (38) sub vm_reg244, 000000C4h
    (DE) mov vm_reg1A4, [vm_reg1A4]
    (A9) mov vm_reg80, vm_reg1C
    (F4) add vm_reg244, 000000C8h
    (D0) mov vm_reg2FC, [vm_reg244]
    (C3) add vm_reg2FC, vm_regDC
    (37) add vm_reg80, vm_reg2FC
    (B3) sub vm_reg244, 000000C8h
    (19) mov vm_reg80, [vm_reg80]
    (98) mov vm_regAC, vm_reg1C
    (5E) add vm_reg244, 000000CCh
    (56) mov vm_reg2FC, vm_reg244
    (C3) add vm_reg2FC, vm_regDC
    (C3) add vm_regAC, vm_reg2FC
    (72) sub vm_reg244, 000000CCh
    (19) mov vm_regAC, [vm_regAC]
    (66) mov vm_reg1F4, vm_reg1C
    (4E) add vm_reg244, 000000D0h
    (97) mov vm_reg2FC, [vm_reg244]
    (64) add vm_reg2FC, vm_regDC
    (C3) add vm_reg1F4, vm_reg2FC
    (B3) sub vm_reg244, 000000D0h
    (A6) mov vm_reg1F4, [vm_reg1F4]
    (85) mov vm_reg2F4, vm_reg1C
    (4E) add vm_reg244, 000000D4h
    (D6) mov vm_reg2FC, [vm_reg244]
    (37) add vm_reg2FC, vm_regDC
    (64) add vm_reg2F4, vm_reg2FC
    (52) sub vm_reg244, 000000D4
    (A6) mov vm_reg2F4, [vm_reg2F4]
    (66) mov vm_regF4, vm_reg1C
    (26) add vm_reg244, 000000D8h
    (97) mov vm_reg2FC, [vm_reg244]
    (64) add vm_reg2FC, vm_regDC
    (93) push vm_reg8
    (43) mov vm_reg10, 00000000h                            <---- silent update in vm_context
    (0B) add vm_reg3F4, AD3AC892h                           <---- wrongly decoded instruction, due to "silent" update
    This disassembly doesn't give too much hint when doing it staticaly, but when performing it in the live process it makes much more sense. Well especially part where magic filed in vm_context is silently updated... funny... with static tracing this can be located easily as you will get bunch of wrong disasm(last instruction in static tracing), but with properly decoded vm (eg. emulated in live process where we have access to whole progy memory) this lille trick wouldn't even be noticed + we could simply put (in case of emulation) our code instead of making file 40mb larger. Does this count as an owning? Or we have to restore x86 opcodes back... let me know

    for comparing reasons, vm emulator 38kb, all stuff dumped ~20mb... in both cases protection is defeated, but... we make user friendly dump with extra 38kb of code, neet isn't it

    anyway I'm off to play some poker... that thingie is addictive

    aaaaaand game goes on:

    (24) mov vm_reg3C8, 0424448Bh
    (11) mov vm_reg3CC, 08244C8Bh
    (24) mov vm_reg3D0, 0004C969h
    (DB) mov vm_reg3D4, 30800000
    (DA) mov vm_reg3D8, FAE240F1
    (AA) mov vm_reg3DC, 505A5958h
    (AA) mov vm_reg3E0, 9090C351h
    (24) mov vm_reg320, F1F17899h
    (24) mov vm_reg324, 85706DF1h
    (DB) mov vm_reg328, F179F5D5
    (6C) mov vm_reg32C, 6C61F1F1h
    (E2) mov vm_reg330, D5957CA9h
    (11) mov vm_reg334, D5ED780Dh
    (9F) mov vm_reg338, 2ED453FEh
    (D8) mov vm_reg33C, 7A0E0E0Eh
    (E2) mov vm_reg340, 957CD5EDh
    (6C) mov vm_reg344, 3270F5D5h
    (DA) mov vm_reg348, F1F1F1A9
    (24) mov vm_reg34C, D5DD70A5h
    (AA) mov vm_reg350, F1F1F1F1h
    (24) mov vm_reg354, F5D5957Ch
    (AA) mov vm_reg358, 70A5F278h
    (E2) mov vm_reg35C, F195D5DDh
    (F9) mov vm_reg360, 957CF1F1h
    (D8) mov vm_reg364, 1D70F5D5h
    (DA) mov vm_reg368, F1F1F1F5
    (AA) mov vm_reg36C, 4AD5ED78h
    (E2) mov vm_reg370, 1220F5E8h
    (E2) mov vm_reg374, 02700D82h
    (DB) mov vm_reg378, 3653F99B
    (43) mov vm_reg37C, AAD5EDD8h
    (E2) mov vm_reg380, 61616132h
    (11) mov vm_reg388, 00000019h
    (66) mov vm_reg38C, vm_reg14
    (1A) add vm_reg38C, 00000320h
    (93) push vm_reg388
    (93) push vm_reg38C
    (98) mov vm_reg38C, vm_reg14
    (9B) add vm_reg38C, 000003C8h
    (8F) call vm_reg38C
    (F9) mov vm_reg388, 4A35B626h
    (87) sub vm_reg2FC, vm_reg58
    (C3) add vm_regF4, vm_reg2FC
    Let's see what is going on when reg38C is executed:

    seg000:018C03C8                 mov     eax, [esp+4]
    seg000:018C03CC                 mov     ecx, [esp+8]
    seg000:018C03D0                 imul    ecx, 4
    seg000:018C03D6 __more_bre_dekriptujeme:                ; CODE XREF: seg000:018C03DAj
    seg000:018C03D6                 xor     byte ptr [eax], 0F1h
    seg000:018C03D9                 inc     eax
    seg000:018C03DA                 loop    __more_bre_dekriptujeme
    seg000:018C03DC                 pop     eax
    seg000:018C03DD                 pop     ecx
    seg000:018C03DE                 pop     edx
    seg000:018C03DF                 push    eax
    seg000:018C03E0                 push    ecx
    seg000:018C03E1                 retn
    and code which is being decrypted:

    seg000:018C0320                 push    89h ; ''
    seg000:018C0325                 pushf
    seg000:018C0326                 xor     dword ptr [esp+4], 88h
    seg000:018C032E                 nop
    seg000:018C032F                 popf
    seg000:018C0330                 pop     eax
    seg000:018C0331                 lea     esp, [esp-4]
    seg000:018C0335                 mov     [esp], ebx
    seg000:018C0338                 cpuid
    seg000:018C033A                 and     eax, 0FFFFFFDFh
    seg000:018C033F                 mov     ebx, [esp]
    seg000:018C0342                 lea     esp, [esp+4]
    seg000:018C0346                 add     ebx, 58h ; 'X'
    seg000:018C034C                 push    esp
    seg000:018C034D                 sub     dword ptr [esp], 0
    seg000:018C0354                 lea     esp, [esp+4]
    seg000:018C0358                 mov     [ebx], eax
    seg000:018C035A                 push    esp
    seg000:018C035B                 sub     dword ptr [esp], 64h ; 'd'
    seg000:018C0362                 lea     esp, [esp+4]
    seg000:018C0366                 sub     esp, 4
    seg000:018C036C                 mov     [esp], ebx
    seg000:018C036F loc_18C036F:                            ; CODE XREF: seg000:018C0374j
    seg000:018C036F                 mov     ebx, 0E3D10419h
    seg000:018C0374                 jnb     short near ptr loc_18C036F+3
    seg000:018C0376                 xor     ebx, 0C7A2086Ah
    seg000:018C037C                 sub     [esp], ebx
    seg000:018C037F                 pop     ebx
    seg000:018C0380                 retn
    basicaly this is hiden cpuid check, and value of cpuid is stored to vm_reg58, later on in virtual machine, right after call vm_reg we have this code:

    (87) sub vm_reg2FC, vm_reg58
    (C3) add vm_regF4, vm_reg2FC
    vm_reg2FC already has imm+cpuid value, so here we have yet another vm anti-dump...

    some API redirection:

    (85) mov vm_regF0, vm_reg1C
    (7A) add vm_regF0, 00000024h      <-- eip offset
    (D0) mov vm_regF0, [vm_regF0]     <-- get ret addy
    (B4) mov vm_regF4, vm_reg1C
    (C4) add vm_regF4, 00000028h
    (F0) mov [vm_regF4], vm_regF0     <-- save ret addy
    (34) single-step check
    (29) mov vm_regF4, vm_reg1C
    (A8) add vm_regF4, 00000024h
    (F9) mov vm_reg90, 10FC5180h
    (19) mov vm_reg90, [vm_reg90]     <-- get api from 10FC5180h
    (FB) mov [vm_regF4], vm_reg90     <-- save it to eip
    (8B) vm_exit                      <-- and we go on...
    API executed from 10FC5180h:

    .idata:10FC5180 ; DWORD GetCurrentThreadId(void)
    .idata:10FC5180                 extrn GetCurrentThreadId:dword
    basically when translated to something user friendly = call dword ptr[10FC5180]

    game continues

    Updated October 17th, 2007 at 18:03 by deroko

  6. ВМВаре видимо се : vmware detection

    well I have posted this like 2 months ago, and source of poc is available for a while, but just to write something interesting here we go again.

    Whole story started when TiGa was trying to detect presence of virtual machine using timers, trick was to know if rdtsc is hooked by playing with cr4 and installing own int 0D handler. In fact I answered with a simple poc code to detect all known public implementations of rdtsc faking driver. (I usually don't like to present way of detection, without way to fight it back )

                            .model  flat, stdcall
    include                 c:\tasm32\include\
    include                 c:\tasm32\include\
    public C start
    nothooked               db      "rdtsc not hooked", 0
    hooked                  db      "rdtsc hooked", 0
    start:                  push    offset sehhandle
                            push    dword ptr fs:[0]
                            mov     dword ptr fs:[0], esp
                            or      dword ptr[esp], 100h
    __safenop:              nop
                            pop     dword ptr fs:[0]
                            add     esp, 4
                            call    ExitProcess, 0
    sehhandle:              mov     eax, [esp+0ch]
                            cmp     [eax.context_eip], offset __safenop
                            jne     __badbad
                            call    MessageBoxA, 0, o nothooked, 0, 0
                            call    ExitProcess, 0
    __badbad:               call    MessageBoxA, 0, o hooked, 0,0 
                            call    ExitProcess, 0
                            end     start
    Trick consist of setting TF and seeing where exception is generated. All of public implementations, yes, including mine too, had a lille flaw, it didn't tace care of TF when used, all of them used add [esp.reg_Eip], 2 which resulted in int 1 to be generated after instruction after rdtsc if TF is set. This could be used to detect all public implementations of fake rdtsc drivers. When rdtsc is executed we have to check if TF is set in eflags, if so, we have to call int 1 handler (default KiTrap01).

    Oki trick, was good, and I knew we have one way to detect all public fake rdtsc driver. But to be honest I was shocked when Archer author of PhantomOlly and QuickUnpack reported that VmWare even without any kinda of driver got "rdtsc hooked" message. This simply means that vmware didn't take care of privileged instruction which by default is not privileged(rdtsc) and when TF is set. So we got one way to detect 100% sure if vmware is active and in such viri can detect if they are runned in vmware. I highly doubt that malware analysers are using any kinda of fake rdtsc drivers as they don't need them So, my comrades, we have one more way to make viri analysing a lille bit harder in vmware

    wondering if vmware team will fix this flaw in next release till then you may write driver to handle rdtsc properly in vmware

    Updated October 7th, 2007 at 07:39 by deroko

  7. Свету се немодзе угодити

    Мислим се стварно како људима више не досади да врте ону тему око "поседовања" неке шуљаве заштите. Али што ћете, свету се немодзе угодити. (тастатура ми нема ДЗ слово )

    Но мимо тога, хтедох нешто корисно да постујем, а то је налазење оепа код тхемида (илити дмида). Трик је веома прост и хајде да га показем набрзака. Фора је у процеисрању грешака, наиме дмида поставља свој сех хандлер како би контролисала извршавање ту и тамо грешака које сама себи баца. Међутим, пре него што скочи на оеп она ће вратит назад сех хандлер који је постојао тј. постављен приликом извршавања трида:

    [*] Starting target process again
    [*] FS : 0x7FFDF000
    [*] sehhandle ptr : 0x0012FFE0
    малко праћења где дмида поставлља свој сех хандлер:

    [*] seh : 0x0012FFE0 EIP return : 0x7C809B67
    [*] seh : 0x0012FFE0 EIP return : 0x00601A0B
    [*] seh : 0x0012FFE0 EIP return : 0x0060A538
    [*] seh : 0x0012FF9C EIP return : 0x0060B2E6
    [*] seh : 0x0012FF9C EIP return : 0x00601A0B
    и на крају пре оепа:

    [*] seh : 0x0012FF9C EIP return : 0x00680D7C
    [*] seh : 0x0012FF9C EIP return : 0x00681BD8
    [*] seh : 0x0012FFE0 EIP return : 0x00401000 <----- бинго :)
    [X] Target terminated...
    Кад таргет има вм оеп онда је по мојем истразивању други еип ретурн из вм-а, али све у свему да се лако лоцирати.

    То је то, укратко о брзом налазењу оепа код дмида... горе је био употрбљен оутпут из мог трејсера, али битно је да се види логика

    English ver
    Title: The world can not be pleased

    I'm really impressed that people do not get boread talking about "owning" some average protection, but world can not be pleased.

    Anyway, I planed to show something interesting, this is the trick of locating themida oep very very fast

    Each thread will setup it's own seh in kernel32.dll prior to it's executin (apc -> LdrInitializeThunk -> k32!BaseThreadStart). Oki, while I was writing my tracer for themida I used int 3h to break at the oep, i3here on in sice worked fine and softice would popup, no matter where int 3h occured. On other hand, when I wanted to break with olly using same trick, by simulating exception, themida would simply throw me back MessageBox with some internal exception (yes, themida seh picked up this int3), but this wasn't the case if I simulated exception at the oep. So new idea was born to trace themida till the oep:

    1. log where seh handler is changed
    2. wait when it is restored

    [*] Starting target process again
    [*] FS : 0x7FFDF000
    [*] sehhandle ptr : 0x0012FFE0
    seh installed to protected app from exceptions:

    [*] seh : 0x0012FFE0 EIP return : 0x7C809B67
    [*] seh : 0x0012FFE0 EIP return : 0x00601A0B
    [*] seh : 0x0012FFE0 EIP return : 0x0060A538
    [*] seh : 0x0012FF9C EIP return : 0x0060B2E6
    [*] seh : 0x0012FF9C EIP return : 0x00601A0B
    and then prior to the oep:

    [*] seh : 0x0012FF9C EIP return : 0x00680D7C
    [*] seh : 0x0012FF9C EIP return : 0x00681BD8
    [*] seh : 0x0012FFE0 EIP return : 0x00401000 <----- bingo :)
    [X] Target terminated...
    Of course, all this eip returns are hooked themida vm interpreter as themida will jmp from vm to the oep. It can be vm oep, or normal oep, depending on protection options

    Updated October 5th, 2007 at 19:54 by deroko (added english version at the bottom)

  8. Блогујем ја, блогујеш ти....

    Блогујем ја, блогујеш ти, блогујемо сви због изгубљене љубави... блогујем...

    Updated October 3rd, 2007 at 16:41 by deroko

Page 2 of 2 FirstFirst 12