Most Popular Blogs

  1. Some Quick Insights Into Native .NET exe's (part 1 of?)

    So, what are natively compiled .NET exes? Well, to answer that question we have
    to go back to how the .NET runtime works.

    All your VB.NET and C# code is translated during compilation from the language
    in question to MSIL (Microsoft Intermediate Language). This is a sort of stack
    based assembler variant that, in combination with metadata present in the executable,
    can be translated back into high level code ( and C#). This is why tools
    such as reflector and dotDecompile exist on the .NET platform; the same effect
    is much harder to achieve with native code.

    Basically, the new possibilities for decompilation introduced in the .NET
    architecture have caused a lot of companies to shit themselves. Intellectual
    property (IP) is the lifeblood of the company. If someone can rip the idea and
    or source out of your product, and implement it in theirs, there is very little
    you can do to prevent them. This is becoming a major issue in the .NET dev circles
    (along with the fact that decompilation = easier cracking for malicous reverse
    engineers bent upon pirating goods to disrupt the global economy and plunge the
    world into deep recession).

    So, .NET devs are a lot more willing to invest time and money in securing their
    products. Frankly, given how shitty 99% of the "security" products on the market
    are, they're wasting their time.

    One of the security products that in my opinion falls into the "not well thought
    out" category is anything that boasts security through native code. Look at it this
    way: hackers have been cracking native code for how long? 2 decades? 3 decades?
    What makes you think that all of a sudden, in the grand year of 2008, they will
    start having problems hacking native code? Maybe it will be even EASIER for them
    because they no longer have to adapt to the foreign .NET architecture, but now
    simply have to load the exe into Olly and go at it the "old fashioned way".

    So, back to the question at hand. What are natively compiled .NET exes? Basically,
    they are exe's containing platform specific code that has been produced by the JIT
    instead of the aforementioned MSIL code. This makes it impossible to decompile the
    .NET code the old fashioned way (with Reflector).

    Producing .NET exes isn't really that simple. To natively compile a .NET exe into a
    native exe, you must use ngen.exe (comes with the SDK). Ngen is a native code
    generator provided by M$, and it's purpose is to increase performance. An application
    that demands performance might use Ngen to compile itself during installation.

    The newly produced native executables are not runnable. In fact, they are not even
    valid Win32 applications. They may be located in the Global Assembly Cache (GAC) of
    the local machine where Ngen was executed. If you do not know what the GAC is, read
    up on it here:

    Demystifying the .NET Global Assembly Cache
    By Jeremiah Talkar

    Now, I guess you're anxious to see the native exes I was just talking about. Desafortunadamente,
    it is not possible for you to access the GAC with Windows explorer right away. Thankfuly,
    a quick registry fix from the article quoted above will lets us browse the GAC from
    Windows Explorer. I quote:

    "If you want to disable the Assembly Cache Viewer and see the GAC in all its naked glory
    within Windows Explorer, you can set HKLM\Software\Microsoft\Fusion\DisableCacheViewer [DWORD] to 1."

    Simple, eh? Now, take any exe .NET exe (for example helloworld.exe) and execute Ngen upon it:

    C:\Windows\system32>cd C:\temp

    C:\temp>ngen HelloWorld.exe
    Microsoft (R) CLR Native Image Generator - Version 2.0.50727.1433
    Copyright (c) Microsoft Corporation. All rights reserved.
    Installing assembly C:\temp\HelloWorld.exe
    Compiling assembly C:\temp\HelloWorld.exe ...
    HelloWorld, Version=, Culture=neutral, PublicKeyToken=null <debug>

    Press any key to continue . . .

    There, we Ngen'd HelloWorld.exe. Now, whenever we execute HelloWorld.exe, the JIT will load
    the native HelloWorld.exe from the GAC and execute it, instead of compiling the IL in the
    HelloWorld.exe we are double clicking on. Like I said, this is intended to improve performance.

    To find the native compiled HelloWorld.exe on our hard drive, browse to

    This is different on each computer.

    You should see one file, and that is: As I mentioned before, it is this file
    that is loaded as a module when the JIT executes.

    As you can see by double clicking on, it is not a valid image. This means that
    you cannot distribute it. That is one of the downfalls of Ngen.exe. You must have a valid exe
    with MSIL in it to generate an Ngen image. You cannot simply distribute the Ngen'd image as it
    is invalid.

    Salamander .NET Protector changes all this. This is one of the protectors that takes a somewhat
    amusing approach towards solving the problem of invalid Ngen'd images. I took a quick look at it
    by downloading the Scribble Demo from their homepage:
    (no reversing involved, reversing is illegal you know :P )

    Just look at the file paths in the link above:

    \scribble-native\mdeployed\C\WINDOWS\assembly\NativeImages_v2.0.50727_32\Scribble\eccb67b11447c9488a7a35bab51a a59b

    It will become quite obvious that all its doing is
    emulating the GAC. It has its own GAC in there, with all the components scribble (native compiled)
    needs. When you run scribble.exe, it initializes the .NET Jit and points it towards its own GAC. .NET
    then grabs everything it needs from there (including native compiled scribble(, and executes it.

    Now that's just a hypothesis on how it works. Without real reversing I cannot verify my results.
    And since reversing it would be illegal, I guess I'll have to pass up the opportunity this time :P

    Now, how secure is salamander .net protector? Well, I guess compared to MSIL code native code is 10x more secure, but
    does that mean that its really SECURE? Not necessarily.

    First of all, there is a small bug in the protector where it makes it preserve the IL code from the original exe. Ntoskrnl
    described it in his article that he did on salamander .net protector. You can find it here:

    But lets just ignore the IL code in memory for now, and focus on attacking the native code. Remember that HelloWorld.exe from
    earlier in the chapter? Let's try Ngenning that, and then having some fun with it :>

    First off, we need both need to be looking at the same HelloWorld.exe. Here is the code that I used, just paste it into an
    empty project and compile. For button1 you can put any button, so long as it executes the code below
    BTW, for the purposes of this project I used express 2008

    Public Class Form1
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        End Sub
    End Class
    Simple piece of work, eh? Will just pop out a messagebox saying Greetings, and that's that. Compile it, run it, and then
    proceed to the next paragraph of this article.

    Ok now, first of all lets generate a valid native image for HelloWorld.exe. Just do:

    > ngen HelloWorld.exe

    Now go to the global assembly cache

    > cd C:\Windows\assembly\NativeImages_v2.0.50727_32\HelloWorld\355240658e5a51e36767993bef4ed510

    , find, and copy it to some temporary folder.

    Now do:

    > ngen uninstall HelloWorld

    I know this might not make sense to you, but just bear with me.

    Now, take Olly, and open the original HelloWorld.exe (the one which we execute ngen upon). Find the IL code in the hex view
    window (IL code is easy to recognize from a hex editor once you get used to looking at it; if you're having trouble finding
    it in the exe gets its RVA with CFF Explorer orjust search for 2A (2A is the bytecode for the IL_Ret instruction)). Here is
    how the beginning of the IL code looks for me from Olly:

    00E221C0  13 30 02 00 3B 00 00 00  0.;...
    00E221C8  1B 00 00 11 00 7E 0D 00  ...~..
    00E221D0  00 04 14 28 58 00 00 0A  .(X...
    00E221D8  0C 08 2C 20 72 0B 01 00  ., r.
    00E221E0  70 D0 09 00 00 02 28 25  pÐ...(%
    00E221E8  00 00 0A 6F 59 00 00 0A  ...oY...
    00E221F0  73 5A 00 00 0A 0B 07 80  sZ...€
    00E221F8  0D 00 00 04 00 7E 0D 00  ....~..
    00E22200  00 04 0A 2B 00 06 2A 00  ..+.*.

    end of IL code:

    (scroll down)

    00E22A10  00 00 04 02 7B 0C 00 00  ..{...
    00E22A18  04 14 FE 01 16 FE 01 0B  þþ
    00E22A20  07 2C 0D 02
  2. Few words about Kraken

    Kraken is the word of the month for sure, but it has nothing to do with the beast from an old nice book written by Jules Verne, Twenty Thousand Leagues Under the Sea.
    The word refers to a series of malwares, something like the Storm trojan, but with much more strength. Kraken seems to be out from August 2006, but until today I’ve never heard about it. Some days ago I read an article (,289142,sid14_gci1308645,00.html) about it, the interesting part is here:
    “One somewhat interesting feature of the code is that the binary is not packed, as many malware binaries tend to be. However, Royal said that the code does have some other forms of obfuscation that make it difficult to analyze completely.”. I decided to look at it.

    I’m not going to give out a detailed explanation about the sample I’m working on (MD5 = 592523a88df3d043d61a14b11a79bd55), but I’ll spend some words on the “forms of obfuscation” used by the malware.

    Detectors are not able to recognize any specific packer/protector. The file is not packed, but from the first lines of code it’s pretty easy to understand that a sort of obfuscation/encryption was included inside the file. I have not found interesting imports/strings, so I tried running the malware. Just to be sure to retrieve some useful information I started logging all API(s) called by the malware.
    The malware calls some nice functions. Almost all the code of the binary file has been decrypted at runtime. The malware spawns one file and it deletes itself, you can spy the decrypted code but I didn’t get anything useful from it. The best thing to do is to look at the code trying to identify a general obfuscation scheme or a decryption routine. Don’t think to trace the entire exe, it’s madness!

    In case like this one, if you are able to see a light over your head you are lucky, otherwise you can step and look at each instruction for the eternity. I was lucky… the real code has been hidden behind a virtual machine. I’m not a virtual machine expert for sure, I only read some articles about this kind of protection.
    I won’t rebuild the entire machine, I’ll give out my findings only. If you think they are wrong and/or you want to add some more information about the virtual machine I’ll be happy to see a comment from you.

    Like every virtual machine out there, after a little initialization it goes into a semi-infinite loop that starts at 4012DA. It simply selects a virtual machine instruction and jump to the code to run. There are a lot of instructions inside the loop, avoiding some junk code you can see the snippet used to select (and then jump to) the next instruction to execute:
    004012E4 MOV AL,BYTE PTR DS:[ESI-1] // Byte pointed by esi-1 decides everything
    004012F3 ADD AL,BL
    0040F807 DEC AL
    004103D9 DEC ESI   // Shift to the next byte
    004103E7 ROL AL,2
    004103F7 DEC AL
    0040F590 XOR AL,0CF
    0040F594 SUB AL,6B
    004104A6 ADD BL,AL
    004104AF MOVZX EAX,AL
    004104B7 MOV ECX,DWORD PTR DS:[EAX*4+40FABB]   // EAX = index of the selected instruction
    004104C6 NOT ECX
    0040129C ROR ECX,1C
    00410213 SUB ECX,4DCBE90C
    0041021F ROL ECX,7
    00410229 INC ECX
    0041070D BSWAP ECX
    00401195 ADD ECX,5E1E81EF
    0040119C XOR ECX,77B911BC
    004011AE NOT ECX
    0041071B ADD ECX,60334BE6   // ECX = address of the selected instruction
    0040FFFF RETN 4C   // Go to the selected instruction

    Everything starts from the value stored inside the buffer pointed by (esi-1), the buffer contains a series of bytes and they are used to select the virtual machine instruction to execute (Moreover they are used to retrieve one or more vm_instruction’s operand). The new value stored inside EAX (obtained after some minor operations) is used to retrieve a dword value, EAX represents the index of the vector that starts at 0×40FABB. As you can see from the code above the new value is used to obtain the address of the vm_instruction to execute.
    Unlike a classical virtual machine this one doesn’t have a clear Instruction Table, spying the dead list from your favorite disassembler you won’t see the address of every single vm_instruction. The Instruction Table has been crypted and the first entry is located at 0×40FABB (there are 256 entries).
    The virtual machine has 16 registers (from r_0 to r_15), they can be used to store byte, word or dword data. EDI register points to the first one, the registers are stored in memory consecutively starting from r_0 to r_15.
    The virtual machine has a stack with a fixed size, EBP register contains the vm_esp value. After almost all push vm_instructions there’s a stack overflow check. The alignment is two bytes, “push byte_value” is not allowed and to push a single byte the virtual machine will extend the byte to a word value.

    Is there a cmp/test instruction inside the snippet? Is there a reference to a vm_eip register? Seems like this virtual machine doesn’t need them. vm_eip is replaced by (esi-1), it’s not an eip per se but it *guides* the virtual machine. I haven’t all the vm_instructions on my notes but I think there are no direct cmp/test instructions. Seems like they are not included inside the virtual machine, strange.

    From what I have seen there are more than 45 vm_instructions included in the virtual machine, to identify each vm_instruction you have to remove a lot of junk code. Once you have all the vm_instructions it’s not immediate to understand what the malware is trying to do.
    Example: here are the vm_instructions used to patch a dword at 0×41CE06 (1° column represents the initial address of the vm_instruction, 2° column represents the name I gave to the vm_instruction):
    401028: push_dword val      //    push F440C1CB
    401028: push_dword val      //    push 8040414A
    40F5BE: nor_stack           //    The value at vm_esp+4 is updated with a nor(vm_esp+4, vm_esp) operation
    4105FA: pop_dword r_i       //    r_15 = 0×00000202
    40F36F: push_dword r_i      //    r_0 = 0×0041CE05
    401028: push_dword val      //    push 98754A9F
    401028: push_dword val      //    push 43179031
    40F198: push_dword vm_esp   //    push vm_esp
    401396: mov_stack_pstack    //    mov dword ptr [vm_esp], dword ptr [dword ptr [vm_esp]]
    40F25C: pop_word r_i        //    r_14 = 0×00009031
    401028: push_dword val      //    push 678AB562
    40F198: push_dword vm_esp   //    push vm_esp
    40FEF3: push_bdword val     //    push 0×00000006, push a dword but the last 24 bits are 0, so it’s like a push byte extended to dword
    410452: add_stack           //    add dword ptr [vm_esp+4], dword ptr [vm_esp]
    4105FA: pop_dword r_i       //    r_15 = 0×216
    40F0A0: pp_mov_dword        //    mov dword ptr [pop t1], (pop t2)
    40F25C: pop_word r_i        //    r_11 = 0×015E4317
    410452: add_stack           //    add dword ptr [vm_esp+4], dword ptr [vm_esp] <– 98754A9F + 678AB562 = 1
    4105FA: pop_dword r_i       //    r_14
    410452: add_stack           //    add dword ptr [vm_esp+4], dword ptr [vm_esp] <– 41CE05 + 1 = 41CE06
    4105FA: pop_dword r_i       //    r_15
    410171: mov_stack_pstack    //    mov dword ptr [dword ptr [vm_esp]], dword ptr [vm_esp+4] <– patch

    Quite a simple patch operation, but the author didn’t use the straight way for sure. Believe it or not, this is the nature of the malware. Now you can understand the phrase: “Don’t think to trace the entire exe, it’s madness!”.

    I tried inspecting some more samples of the same Kraken family. There are some similarities/differences:
    - they are protected by a virtual machine too
    - the routine used to select the next vm_instruction is not the same
    - (I think) the vm_instructions are equal, but they are not defined in the same way. I mean, the code used to define a push is not the same but the result is the same infact in both cases you have a push vm_instruction
    - the (encrypted)Instruction Table is not the same. At index i you won’t have the same vm_instruction for malware_x and malware_y
    - the vm protection exists for the spawned file too

    Now I fully understand the words used by the author of the interview, it’s complex to understand what’s going on…
  3. Vmware snapshot and SSDT

    Some time ago I blogged about Vmware snapshots ( introducing a way to recognize hidden files by simply comparing two snapshots. I wanted to extend my research on the subject a little bit more, but I didn’t. I got the opportunity to put my hands on some snapshots again in these days. I haven’t anything on my mind, but I was surprised by some coincidences. Look at the information below:
    80544bc0: 804fc624 00000000 0000011c 804fca98
    80544bd0: bf995ba8 00000000 0000029a bf98f5f8
    80544be0: 00000000 00000000 00000000 00000000
    80544bf0: 00000000 00000000 00000000 00000000

    00544BC0: 24C6 4F80 0000 0000 1C01 0000 98CA 4F80 $.O………..O.
    00544BD0: A85B 99BF 0000 0000 9A02 0000 F8F5 98BF .[..............
    00544BE0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
    00544BF0: 0000 0000 0000 0000 0000 0000 0000 0000 ................


    First 4 lines are taken from Windbg while I was debugging an XP sp1 virtual machine running under Vmware; last 4 lines are taken from a saved Vmware snapshot (same os of course).
    Do you see anything useful? These are KeServiceDescriptorTable[0],[1],[2],[3] and they have of course the same bytes, but there’s something else. There’s a connection between the addresses on the first lines and the offsets on the second ones, just remove the first 2 digits from the address. Do you see it? Look here: 80544BC0/544BC0, 80544BD0/544BD0, 80544BE0/544BE0, 80544BF0/544BF0.

    Seems like the kernel memory is stored inside the snapshot. It’s not totally true indeed, there’s only a part of the kernel memory stored inside a Vmware’s snapshot. All the KeServiceDescriptorTable entries are present btw.
    SSDT is inside the snapshot I have and it’s complete; SSDT Shadow seems to be inside the snapshot too, but there’s no real connection between kernel memory/snapshot addresses and it’s not complete (it needs some more research btw).

    Is it only a coincidence? I tried with some XP machines and the result is the same, it’s possible to obtain real information of SSDT. According to Kayaker’s test it should work on win2k (don’t remember the service pack he was using. Thx K.).

    With this new information it’s pretty easy to code a SSDT revealer. I gave it a try and here is a result:

    You can use the program to display SSDT entries and to find out modified entries too by simply comparing an original snapshot with another one.

    To retrieve information from a snapshot you have to provide the address of KeServiceDescriptorTable[0] (something like 80544BC0, no “0x” prefix), and you have to select the OS of the virtual machine. After that you can:
    1. save an untouched SSDT using the button labelled “Create untouched SSDT”
    2. retrieve SSDT information from a snapshot by simply pushing the button labelled “Get snapshot SSDT”. Checking “Load untouched SSDT data” you can compare the original table (previously saved) with the one from the snapshot you’ll select. If a service has been changed you’ll read the word “YES” in the last column.

    I got the name of the services from this table:
    I can’t test all the OS, if you find one or more errors drop me a mail.
    Following this method it’s also possible to get the list of the running processes/modules, more about this later.

    SSDT from snapshot available here:
  4. antisptd

    antisptd is a driver that makes it possible for softice to load when sptd.sys is present. It uses the method described by Kayaker and that is, by removing the notifyroutine sptd sets to prevent ntice.sys to load. After ntice.sys gets loaded, it restores the notifyroutine and the keyboard hooks in i8042prt.sys that have been screwed by the sptd.sys.

    Just put the startsi.exe in a directory with antisptd.sys and execute startsi.exe.

    The driver should work on XP SP2/SP3 with the latest softice installed. I have no idea if it'll work on XP SP1 (cause I have used hardcoded values to locate the patch locations in i8042prt.sys). If it doesnt work, feel free to modify the sources and recompile the driver yourself.
    Attached Thumbnails Attached Files
  5. Inside SetUnhandledExceptionFilter


    is frequently used as Anti Debug Trick, especially in Malware Applications. Around here there are various plugins for Olly that allows the Reverser to trasparently debug this kind of protection, so there is not a real necessity add other words about the mere practical part of trick overcoming.

    Due to the fact that today, too many young reversers uses a ton of plugins anti - anti - xxx without knowing how internally they works, I decided to expose here a little summary of SetUnhandledExceptionFilter Internal characteristics.

    First of all, what SetUnhandledExceptionFilter is? according to MSDN documentation:

    Enables an application to supersede the top-level exception handler of each thread of a process.

    After calling this function, if an exception occurs in a process that is not being debugged, and the exception makes it to the unhandled exception filter, that filter will call the exception filter function specified by the lpTopLevelExceptionFilter parameter.

    And this is the Syntax:

    __in  LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
    lpTopLevelExceptionFilter is a pointer to top-level exception filter function that will be called whenever the UnhandledExceptionFilter function gets control, and the process is not being debugged. A value of NULL for this parameter specifies default handling within UnhandledExceptionFilter.

    Usually, in absence of an UnhandledExceptionFilter the topmost handler called when an uncatched exception occours, is the default one provided by Windows Itself, the classical MessageBox that advices the user that an Unhandled Exception has occured.

    But Windows allow programs to use custom Handlers for UnhandledException. The core of the trick is here, if the application is NOT debugged, the application is able to call the Custom Handler, but if the application IS debugged the Custom Handler will be never called.

    The possibility of cognitive differentiation make obviously able the target application to apply a series of countemeasures against debugging, from detection to code hidding.

    Just remember that due to the architecture of Windows Exception Handling, in every case is called UnhlandledExceptionFilter() function, and this will our point of attack (for anti - anti dbg trick).

    This is the general inner meccanism of SetUnhandledExceptionFilter(), going more deep we observe the call stack of the first thread of any Win32 application, we can see that execution in every case is reported to BaseProcess, here the pseudo definition:

    VOID BaseProcessStart( PPROCESS_START_ROUTINE pfnStartAddr )
            ExitThread( (pfnStartAddr)() );
        __except( UnhandledExceptionFilter( GetExceptionInformation()) )
            ExitProcess( GetExceptionCode() );
    The same thing happens for threads, by referencing to BaseThreadStart:

    VOID BaseThreadStart( PTHREAD_START_ROUTINE pfnStartAddr, PVOID pParam )
            ExitThread( (pfnStartAddr)(pParam) );
        __except( UnhandledExceptionFilter(GetExceptionInformation()) )
            ExitProcess( GetExceptionCode() );
    All that happens inside BaseProcessStart() and BaseThreadStart() for what previously said, will be passed to the UnhandledExceptionFilter().

    It’s now time to see what really is UnhandledExceptionFilter(), according to MSDN:

    An application-defined function that passes unhandled exceptions to the debugger, if the process is being debugged. Otherwise, it optionally displays an Application Error message box and causes the exception handler to be executed. This function can be called only from within the filter expression of an exception handler.


    LONG WINAPI UnhandledExceptionFilter(
      __in  struct _EXCEPTION_POINTERS *ExceptionInfo
    Became clear that UnhandledExceptionFilter represents the last choise for processing unhandled exceptions, so the Check Debugger Presence surely is located inside this function, let’s see a simplified version of this function:

    LONG UnhandledExceptionFilter( EXCEPTION_POINTERS* pep )
        DWORD rv;
        EXCEPTION_RECORD* per = pep->ExceptionRecord;
        if( ( per->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ) &&
             ( per->ExceptionInformation[0] != 0 ) )
            rv = BasepCheckForReadOnlyResource( per->ExceptionInformation[1] );
            if( rv == EXCEPTION_CONTINUE_EXECUTION )
                return EXCEPTION_CONTINUE_EXECUTION;
        DWORD DebugPort = 0;
        rv = NtQueryInformationProcess( GetCurrentProcess(), ProcessDebugPort,
                                        &DebugPort, sizeof( DebugPort ), 0 );
        if( ( rv >= 0 ) && ( DebugPort != 0 ) )
            // Yes, it is -> Pass exception to the debugger
        // Is custom filter for unhandled exceptions registered ?
        if( BasepCurrentTopLevelFilter != 0 )
            // Yes, it is -> Call the custom filter
            rv = (BasepCurrentTopLevelFilter)(pep);
            if( rv == EXCEPTION_EXECUTE_HANDLER )
                return EXCEPTION_EXECUTE_HANDLER;
            if( rv == EXCEPTION_CONTINUE_EXECUTION )
                return EXCEPTION_CONTINUE_EXECUTION;
    As you can see, inside UnhandledExceptionFilter() is called NtQueryInformationProcess() that has as first parameter our process and next DebugPort, this is done to know if the process is debugged.

    All that we have to do to obtain an apparently undebugged process is to modify the first parameter (last pushed at debugging time), in other words we have to change the retur value of GetCurrentProcess() from 0xFFFFFFFF to 0×00000000.

    So remember, when you have to overcome a SetUnhandledExceptionFilter() just put a Breakpoint for UnhandledExceptionFilter() and go inside this function to modify the previously exposed parameter

    Thanks to Oleg Starodumov for pseudocodes

    See you to the next blog post..
  6. SoftICE and KDExtensions

    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:

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

    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:

    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:

    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:

    .text:A7AB9D3A si_callExtension proc near             
    .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                 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!!!!

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

    ULONG   old_fs;
    void    set_fs()
                    xor     eax, eax
                    mov     ax, fs
                    mov     old_fs, eax
                    mov     eax, 30h
                    mov     fs, ax
    void    restore_fs()
                    mov     eax, old_fs
                    mov     fs, ax
    Although those seem like not safe functions, remember that softice ...
  7. Nucleus Framework

    I just released the initial release of nucleus framework. You have to decide if you like it

    Attached Thumbnails Attached Files
  8. Bridge them all

    Today I’m going to tell you something about the last malware I checked (MD5 0C17E03F41289E47EEB5D0F3F1F48C9C).

    The exe file imports few functions only, but the malware calls a lot of APIs. The author uses a special trick to call an API function, he creates a sort of bridge between the first instruction and the rest of the code of the function itself. The first instruction is executed directly from the stack, then a jmp instruction (the bridge) will lead you to the second instruction (and the rest of the code) of the function. I think I’ve already seen the trick somewhere but unfortunately I don’t remember where… maybe a specific packer or just something similar, I don’t know. If you have seen this trick before just drop me a comment, thx!

    The malware is packed, but inside the unpacked file there’s something strange:

    The exe is full of calls to NULL value. I’m pretty sure that it’s not an error occorred during the unpacking process; there’s something at the beginning of the exe able to fix the addresses. I started my analysis from the first lines of the unpacked file.

    The Import Table is really small but spying inside the strings window I found a lot of common API strings. There’s a big list of functions, and they are divided into some groups; one group containing kernel32 functions, another one with user32 and so on. Working a little with some cross references I got the point I was looking for. It’s time to describe how the malware changes all the “call NULL” instructions.

    First of all the malware gains access to kernel32 base address:

    4013D5    mov  edi, large fs:30h  ; PEB
    4013DC    mov  edi, [edi+0Ch]     ; PEB+0x00c   Ldr : Ptr32 _PEB_LDR_DATA
    4013DF    mov  edi, [edi+0Ch]     ; +0x00c InLoadOrderModuleList : _LIST_ENTRY
    4013E2    jmp  short loc_401404
    4013E4 check_current_module:
    4013E4    mov  eax, edi    ; eax points to current _LDR_MODULE structure
    4013E6    add  eax, 2Ch
    4013E9    push [ebp+arg_0]        ; unicode "kernel32.dll"
    4013EC    push dword ptr [eax+4]  ; current module name inside InLoadOrderModuleList
    4013EF    call Compare_UNICODE_Strings
    4013F4    or   eax, eax
    4013F6    jnz  short strings_are_not_equal
    4013F8    mov  eax, edi           ; LDR_MODULE of the module I was looking for
    4013FA    mov  eax, [eax+18h]     ; He gets the BaseAddress!!!
    4013FD    pop  edi
    4013FE    leave
    4013FF    retn 4
    401402 strings_are_not_equal:
    401402    mov  edi, [edi]        ; jump to next module structure
    401404 loc_401404:
    401404    cmp  dword ptr [edi+18h], 0          ; Is BaseAddress 0?
    401408    jnz  short check_current_module
    40140A    xor  eax, eax
    40140C    pop  edi
    40140D    leave
    40140E    retn 4
    Quite common way, but quite uncommon inside a malware… at least from my not so experienced perspective. Anyway, once it has the right BaseAddress tha malware starts bridge-ing all the necessary functions.

    It’s everything inside this call. It takes four parameters, we can ignore the first one pushed into the stack. What about the others?
    - eax represents the BaseAddress of a module, in this case ntdll
    - 404040 points to a sequence of strings, in this case the first one is “RtlZeroMemory”
    - 406000 represents an address inside the malware
    The procedure is called each time the malware needs to bridge a group of functions, all of them belong to a specific module. In this specific case it works with ntdll’s functions. The list of the functions starts from 0×404040 address:

    The routine contains a loop running until all the functions inside the current group are not all bridged. Here is how the first function is bridged (the sub routine starts at 0×401411):
    1. It takes VirtualAlloc starting address via Kernel32’s ExportTable
    2. It gets the number of bytes of the first instruction of VirtualAlloc. On my XP machine VirtualAlloc starts with a two byte length instruction “MOV EDI, EDI”
    3. It subtracts 7 from ESP value. 7 is obtained adding 5 (a fixed value) to the number of bytes of VirtualAlloc first instruction (2+5=7)
    4. It copies the first two bytes of VirtualAlloc’s code inside the word pointed by the new stack pointer value
    5. If the length of the first instruction is one byte only the malware checks for a possible active breakpoint comparing the byte with 0xCC value; quite useless check at this point…
    6. It sets the byte pointed by ESP+2 to 0xE9
    7. It fills the final 4 of 7 bytes obtaining:

    You have the first instruction of VirtualAlloc at 0×12FDF5, then the jump instruction will lead you directly at the second instruction of VirtualAlloc. Now you understand why it decreases ESP value by 7, two bytes for the first instruction and 5 for the jump. Starting from 0×12FDFC you have the old untouched stack.
    8. It gets the length of the first instruction of the function to bridge. In this specific case the name of the function is RtlZeroMemory and the length is 1
    9. It adds 5 to the obtained value
    10. It calls VirtualAlloc passing trought the stack. It calls 0×12FDF5, and it allocs 6 bytes. 6 is the value that comes from point #9 (5+1=6)
    11. It copies the first instruction of RtlZeroMemory inside the allocated memory space
    12. An anti breakpoint check occours this time because the first instruction is one byte only
    13. It sets the second byte inside the allocated memory space to 0xE9 (again, a jmp instruction)
    14. It fills the rest of the bytes:

    Here is the bridge! It’s like what happened to VirtualAlloc, the allocated memory space contains the first instruction of RtlZeroMemory and a jump to the rest of the code
    15. It restores the original stack pointer value simply adding 7 to the current ESP value
    16. It returns the starting address of the allocated memory space (in this case 0×320000)

    To sum up, the routine bridges the function and returns a memory address. The address will be saved starting from 0×406000 which is another parameter passed to the routine. If you don’t remind all the parameters you can take a look some lines above.
    So, starting from 0×406000 you’ll have a series of dwords, each one containing a pointer to a memory allocated space; these are the values used to replace all the NULL calls. Now I finally know why after the unpacking process I still had a series of “call NULL” instructions.

    Is it really necessary to bridge everything?
    Yes if the author wants to fool an automatic analysis. I don’t know if the trick works or not, but it’s the only reasonable thing I can think of.
    On the other hand, he can’t stop a complete human analysis because once you know how it works it’s pretty easy to convert all the “call NULL” instructions into the right ones; a simple idc script will solve the puzzle.

    It’s a nice piece of malware to analyse btw, it has some interesting routines inside!
  9. VMware ring3 detection (RF handling)


    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:

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

    #include        "defs.h"
    PVOID   buffer;
    DWORD   dwExceptionCount;
    ULONG   filter(PEXCEPTION_INFO pei){
            PCONTEXT pctx;
            pctx = pei->pContext;
            if (dwExceptionCount == 0){
                    pctx->Dr7 = BPM_LOCAL_EXACT | BPM0_LOCAL_ENABLED;
                    pctx->Dr0 = (DWORD)buffer;
                    pctx->Eip += 2;
                    NtContinue(pctx, FALSE);
            }else if (dwExceptionCount == 1){
                    pctx->EFlags |= 0x10000;
                    NtContinue(pctx, FALSE);
            }else if (dwExceptionCount == 2){
                    printf("[X] vmware detected\n");
            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]
            printf("[*] vmware not detected\n");

    #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;
    NtContinue(__in PCONTEXT ctx, BOOL Alertalbe);
    typedef struct{
    	PULONG ExceptionCodeAddress;
    	PCONTEXT   pContext;
    	ULONG  ExceptionCode;
    	ULONG  ExceptionFlags;
    	PULONG ExceptionRecord;
    	ULONG  ExceptionAddress;
    	ULONG  NumberOfParameters;

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

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

    Hope you find it usefull
  10. Filter Monitor 1.0.1

    This week, after months of development of bigger projects, I found some time to windbg "ntoskrnl.exe" and write a utility. It is called Filter Monitor and shows some key filters installed by kernel mode components.

    “As you probably all know the Service Descriptor Table has been a playground on x86 for all sorts of things: rootkits, anti-viruses, system monitors etc. On x64 modifying the Service Descriptor Table is no longer possible, at least not without subverting the Patch Guard technology.

    Thus, programs have now to rely on the filtering/notification technologies provided by Microsoft. And that’s why I wrote this little utility which monitors some key filters.

    Since I haven’t signed the driver of my utility, you have to press F8 at boot time and then select the “Disable Driver Signature Enforcement” option. If you have a multiple boot screen like myself, then you can take your time. Otherwise you have to press F8 frenetically to not miss right moment.

    A disclaimer: the boot process can be a bit annoying, but the utility should be used on virtualized systems anyway, as I haven’t fully tested it yet. I doubt that it will crash your system, I guess the worst scenario is that it won’t list some filters. It should work on any Windows system starting from Vista RTM and I have provided an x86 version and an x64 version. But the truth is that I have tested only the x64 version on Windows 7 RTM. Last but not least, I can’t guarantee that this utility will work on future versions of Windows, it relies heavily on system internals.

    Now, let’s run it. The supported filters/notifications at the time are these: Registry, Create Process, Create Thread and Load Image. “Registry” stands for CmRegisterCallback filters. “Create Process” for PsSetCreateProcessNotifyRoutine callbacks. “Create Thread” for PsSetCreateThreadNotifyRoutine callbacks. And “Load Image” for PsSetLoadImageNotifyRoutine callbacks.

    The “Additional Info” in the list view provides internal information like the address of the callback function.

    There are some default filters registered by system components, but, as you can notice, there are also Kaspersky components. That’s because some filters (like the registry filter) are not used by system components and I needed a tool which would make use of these filters for my little demonstration.

    The version of Kaspersky I have installed is the latest one available on the internet which is:

    I created for this demonstration a little executable called “k-test” (what you see on the desktop are three copies of the same executable) which copies itself in a directory called “borda” in the “Roaming” directory of the operating system. It then creates a value in the Run key of the registry to execute itself at each start-up. Finally, it launches itself from the “Roaming” directory and ends.

    This is a typical malware behavior. Beware that the signature of the application itself is not contained in the databases of Kaspersky as I have written it on the fly, but it detects the suspicious behavior, stops execution and deletes the file. And it does this every time I launch the test application.

    Now let’s get to the part where I show an additional functionality of the Filter Monitor which is the ability to remove registered filters and see what happens if I remove the filters installed by klif.sys, which is the “Kaspersky Lab Interceptor and Filter” driver. As the name suggests, this driver intercepts and filters: it installs all four of typologies of filters listed by the Filter Monitor. On x86 instead of calling CmRegisterCallback it additionally hooks about 60 functions of the Service Descriptor Table (which is a lot), but that’s no longer possible on x64.

    So, let’s remove the filters and re-launch k-test. It works now.

    Final disclaimer: It is not my intent to comment on security features of anti-viruses, I just wanted to present my new tool and show its functionalities. I was already familiar with the internals of Kaspersky before writing this utility.

    I hope you enjoyed the presentation.”

    P.S. A huge thanks goes to Alessandro Gario for providing me with all the different versions of ntoskrnl.exe.
  11. DNAScan Malicious Network Activity Reverse Engineering


    This is a paper splitted into two episodes, the first two can be readed here


    Here the Third Part.

    In this blog post we will investigate deeply the effective functionalities of DNAScan,
    that can be seen as a set of Threads that accomplish different networking functionalities like:

    • * Server Functionalities
    • * Client Functionalities
    • * Malicious File Exchange
    • * Generic Backdoor

    Let's start from the beginning of network functionalities setup, initially from the main thread is called WSAStartup used to initiate the Winsock DLL, successively is called a classical socket() and immediately after WSAIoctl

    0040A0EE PUSH 2600
    0040A0F3 PUSH EAX
    0040A0F4 PUSH EBX
    0040A0F5 PUSH EBX
    0040A0F6 PUSH 4004747F
    0040A0FB PUSH ESI
    0040A0FC CALL DWORD PTR DS:[41526C];WSAIoctl

    The WSAIoctl function controls the mode of a socket, works like DeviceIoControl so we have a suite of IO Control Codes, in our case the Control Code is 4004747F that corresponds to SIO_GET_INTERFACE_LIST

    Returns a list of configured IP interfaces and their parameters as an array of INTERFACE_INFO structures. After setting socket options and binding we have another WSAIoctl this time with code 98000001 in this way the socket normal working parameters are modified, indeed 98000001 corresponds to SIO_RVALL that enables a socket to receive all IP packets on the network, to use this application need to be in RAW mode using IP protocol and bound to a specific local adapter. Finished this the first thread is created:

    0040A089 PUSH EAX
    0040A08A PUSH ESI
    0040A08B PUSH EDI
    0040A08C PUSH OFFSET srcdll.00409FCD; Look here to know what thread does
    0040A091 PUSH ESI
    0040A092 PUSH ESI
    0040A093 CALL DWORD PTR DS:[415130]

    after opening this thread the first socket is closed. Now the next important function called is SHGetFolderPath witch sets as folders \user\cookies, finally execution jumps to a secondary thread that contains a recvfrom

    00409F89 PUSH EDI
    00409F8A PUSH EDI
    00409F8B PUSH EDI
    00409F8C PUSH 4000
    00409F91 PUSH ESI
    00409F92 PUSH DWORD PTR SS:[EBP+8]
    00409F95 CALL DWORD PTR DS:[415268];recvfrom

    by watching the buffer out (second parameter) we can see what arrives to DNAScan

    001644B8 E..a......=
    00164518 ACACACACACABN.SMB%.............
    00164538 ............................
    00164558 ......V......\MAILSLOT\BRO
    00164578 WSE...........................

    this recvfrom is repeated until certain conditions that depends from watch application receives,
    under certain conditions sento from server reacts. After setting this is builded another thread that makes use of a classical server architecture

    • * Socket
    • * Listen
    • * Accept

    Next networking operation is the Pipe building

    00407DCF PUSH 0
    00407DD1 PUSH 0
    00407DD3 PUSH 400
    00407DD8 PUSH 400
    00407DDD PUSH 0FF
    00407DE2 PUSH 0
    00407DE4 PUSH 3
    00407DE6 PUSH OFFSET srcdll.004025B4; ASCII "\\.\pipe\ie_down_pipe"
    00407DEB CALL; Jump to kernel32.CreateNamedPipeA
    00407DF0 CMP EAX,-1
    00407DF3 JNE SHORT 00407DF7
    00407DF5 JMP SHORT 00407E58
    00407DFA MOV DWORD PTR SS:[EBP-8],0
    00407E01 PUSH 0
    00407E03 PUSH DWORD PTR SS:[EBP-4]
    00407E06 CALL; Jump to kernel32.ConnectNamedPipe
    This creates a named pipe \\.\pipe\ie_down_pipe and successively Enables a named pipe server process to wait for a client process to connect to an instance of a named pipe.

    At this point is assembled the following string

    00401620 http://%s%s?user_id=%.4u&version_id=%s&passphrase=%s&socks=%lu&v
    00401660 ersion=%lu&crc=%.8x.URL: sniffer_ftp_%s..ftp_server=%s&ftp_login
    004016A0 =%s&ftp_pass=%s&version=%lu.URL: sniffer_pop3_%s..pop3_server=%s
    004016E0 &pop3_login=%s&ftp_pass=%s.URL: sniffer_imap_%s..imap_server=%s
    00401720 &imap_login=%s&imap_pass=%s.URL: sniffer_icq_%s..icq_user=%s&icq
    00401760 _pass=%s.SharedAccess.wscsvc.=.GET_COOK.VER.EXE.DL.DL_EXE.DL_EXE
    004017A0 _ST.REBOOT.\%lu.exe./upd %lu
    as you can see there are a couple of interesting strings like

    • * ftp_pass=%s
    • * imap_pass=%s
    • * sniffer_pop3_%s
    • * sniffer_icq_%s

    0040587D PUSH EAX
    0040587E PUSH DWORD PTR SS:[EBP-4];take a look here
    00405881 PUSH 0
    00405883 CALL; Jump to wininet.FindFirstUrlCacheEntryA

    this api enumerates the Internet cache, to see what comes out just watch the second parameter

    0040588F MOV EAX,DWORD PTR SS:[EBP-4]
    00405892 MOV ECX,DWORD PTR DS:[EAX+4]
    00405895 PUSH ECX
    00405896 PUSH DWORD PTR SS:[EBP+8]
    00405899 PUSH ECX
    0040589A CALL; Jump to shlwapi.StrStrIA
    0040589F POP ECX
    004058A0 OR EAX,EAX
    004058A2 JE SHORT 004058AA
    004058A4 PUSH ECX
    004058A5 CALL; Jump to wininet.DeleteUrlCacheEntry
    004058AA MOV DWORD PTR SS:[EBP-8],1000
    004058B1 LEA EAX,[EBP-8]
    004058B4 PUSH EAX
    004058B5 PUSH DWORD PTR SS:[EBP-4]
    004058B8 PUSH DWORD PTR SS:[EBP-0C]
    004058BB CALL; Jump to wininet.FindNextUrlCacheEntryA
    004058C0 JMP SHORT 0040588B
    004058C2 PUSH DWORD PTR SS:[EBP-0C]
    004058C5 CALL; Jump to wininet.FindCloseUrlCache
    this piece of code scans Url Cache to find the previously seen IP address and if discovered, removes it with DeleteUrlCacheEntry.

    00405937 PUSH EAX
    00405938 PUSH OFFSET srcdll.0040A872; ASCII "
    0040593D PUSH 0
    0040593F CALL; Jump to urlmon.URLOpenBlockingStreamA
    Creates a blocking type stream object from a URL and downloads the data from the Internet. When the data is downloaded the client application or control can read it by using the IStream::Read method.

    By analysing the URL we can extract the following informations:

        * user_id=373125111
        * version_id=17
        * passphrase=fkjvhsdvlksdhvlsd
        * socks=9180
        * version=132
        * crc=00000000
    When you step URLOpenBlockingStreamA be aware that this function presents thread and fiber functionalities to speed up and make an easier analysis approach just detach for one step the New Thread Break Event. If incidentally you have this Event enabled, surf between threads with Execute till Return and Run Actual Thread.

    _Next Thread_

    Here the malicious application scans into C:\Documents and Settings\evilcry\Cookies\ cookie by cookie

    00408305 PUSH DWORD PTR SS:[EBP+8]; ASCII "C:\Documents and Settings\evilcry\Cookies\"
    00408308 PUSH EDI
    00408309 CALL; Jump to kernel32.lstrcpyA
    0040830E MOV EDX,DWORD PTR SS:[EBP-8]
    00408311 LEA EDX,[EDX+2C]
    00408314 PUSH EDX
    00408315 PUSH EDI
    00408316 CALL; Jump to kernel32.lstrcatA
    0040831B PUSH EDI
    0040831C CALL; Jump to kernel32.DeleteFileA
    00408321 PUSH DWORD PTR SS:[EBP-8]
    00408324 PUSH DWORD PTR SS:[EBP-4]
    00408327 CALL; Jump to kernel32.FindNextFileA
    0040832C TEST EAX,EAX
    0040832E JNE SHORT 004082E5
    00408330 PUSH DWORD PTR SS:[EBP-4]
    00408333 CALL; Jump to kernel32.FindClose
    Successively by using ad usual CreateToolhelp32Snapshot and Process32First/Process32Next and WriteProcessMemory DNAScan injects some pieces of code in various system processes. This is essentially not useful for our analysis scopes actually.

    0040795B 55 PUSH EBP
    0040795C 8BEC MOV EBP,ESP
    0040795E 83C4 F8 ADD ESP,-8
    00407961 53 PUSH EBX
    00407962 E8 57F6FFFF CALL 00406FBE
    Inside the call

    00406FC9 PUSH OFFSET srcdll.0040B87E
    00406FCE PUSH 1
    00406FD0 PUSH 0
    00406FD2 CALL; Jump to OLE32.CreateStreamOnHGlobal
    The CreateStreamOnHGlobalfunction creates a stream object that uses an HGLOBAL memory handle to store the stream contents. This object is the OLE-provided implementation of the IStream interface.

    00406FE1 PUSH OFFSET srcdll.0040B87A
    00406FE6 PUSH srcdll.00401B50; ASCII "pstorec.dll"
    00406FEB CALL 00406F71; Loads from pstorec.dll PStoreCreateInstance
    00406FF0 TEST EAX,EAX
    00406FF2 JE SHORT 00407033
    00406FF4 PUSH OFFSET srcdll.0040B882
    00406FF9 PUSH srcdll.00401B73; ASCII "crypt32.dll"
    CALL 00406F71; Loads from crypt32.dll CryptUnprotectData
    00407009 PUSH EAX
    0040700A PUSH EAX
    0040700B PUSH EAX
    0040700C LEA EDX,[40B876]
    00407012 PUSH EDX
    00407013 CALL DWORD PTR DS:[40B87A];PStoreCreateInstance
    Protected Storage (Pstore) is available for use in Windows ...
    Reverse Engineering
  12. Site Relaunch


    The relaunch of my website is now live, it is
    available via the link at the bottom of woodmann
    as usual or the following urls

    In the upcoming week i shall be releasing some
    new articles :-)

    Merry Christmas,

  13. Eeye BinDiffing Trick


    Around here exist truly intersting tools for Binary Diffing, useful for Vulnerability Research and or Malware Analysis.

    The two most famous tools are:

    • Sabre Security BinDiffv2
    • Eeye Binary Diffing Suite (EBDS)

    The eEye Binary Diffing Suite (EBDS) is a free and open source set of utilities for performing automated binary differential analysis, but has a little problem, seems to be explicitly developed for IDA 5.0, and no other IDA’s versions are supported.

    But there is a trick to avoid that an make it working with all IDA’s Versions.

    Open with Regedit the following RegKey:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IDA Pro_is1

    And change the Key Entry DisplayName with the string IDA Pro Standard v5.0 or IDA Pro Professional v5.0


    Happy Diffing

    See you to the next post..
  14. Inside DeleteFiber() as Anti Debug Trick


    Malware is often really boring to reverse because in high percentage they implements basical well known mechanisms of infection and self protection.
    But sometimes there are really intersting malware that implements innovative techniques, this is the case of a trojan borned into 2006 that implemented DeleteFiber() as Anti–Debug Trick in a really easy and smart way.

    To understand how it works, let's see whar DeleteFiber is, directly from MSDN:

    Deletes an existing fiber.


    VOID WINAPI DeleteFiber(
      __in  LPVOID lpFiber
    lpFiber is the address of the fiber to be deleted.

    Important to say that the DeleteFiber function deletes all data associated with the fiber. This data includes the stack, a subset of the registers, and the fiber data.

    Now let's see a basical use of DeleteFiber():

    #define _WIN32_WINNT 0x0400
    #include <windows.h>
    int main(void)
    	char fiber[1024] = {0};		
    	return EXIT_SUCCESS;
    After showing the basical use of DeleteFiber let's see how can be implemented as Anti-Debug Trick, I insert here direcly the code:

    #define _WIN32_WINNT 0x0400
    #include <windows.h>
    #include <stdio.h>
    int main(void)
          char fib[1024] = {0};	
    	if(GetLastError() == 0x00000057)
    		MessageBoxA(NULL,"This process is NOT debugged","Info",MB_OK);
    		MessageBoxA(NULL,"This process IS debugged","Info",MB_OK);
    	return EXIT_SUCCESS;
    As you can understant we can resume this trick into two cases:

    If the process is NOT debugged DeleteFiber give us an Error Code of 0x00000057 that corresponds to ERROR_INVALID_PARAMETER
    If the process IS debugged the error code is differs from 0x00000057

    What to say it's really easy to implement and really effective for all kind of debuggers, with a bit of junk code that confuses ideas the conditional check could be placed really distant from the DeleteFiber() itself.

    Inside DeleteFiber()

    Now we will see how DeleteFiber internally works to understand why this should be used as Anti-Debug trick.

    This is the Dead List:

    00401000  PUSH DF.00403370
    00401005  CALL DWORD PTR DS:[<&KERNEL32.DeleteFiber>;  kernel32.DeleteFiber
    inside DeleteFiber()
    7C825A9F >   MOV EDI,EDI          ; DF.00403778
    7C825AA1     PUSH EBP
    7C825AA2     MOV EBP,ESP
    7C825AA4     PUSH ECX
    7C825AA5     PUSH ESI
    7C825AA6     MOV EAX,DWORD PTR FS:[18]     ;_TEB Struct
    7C825AAC     MOV ECX,DWORD PTR DS:[EAX+10] ;pointer to _TIB.FiberData field
    7C825AAF     MOV ESI,DWORD PTR SS:[EBP+8]  ;lpFiber
    7C825AB2     CMP ECX,ESI
    7C825AB4     JE kernel32.7C826596          ;ExitThread if( FiberData == lpfiber)
    7C825ABA     AND DWORD PTR SS:[EBP-4],0    ;Clears this Stack location
    7C825ABE     PUSH 8000                     ;MEM_RELEASE
    7C825AC3     LEA EAX,DWORD PTR SS:[EBP-4]  
    7C825AC6     PUSH EAX
    7C825AC7     LEA EAX,DWORD PTR DS:[ESI+10]
    7C825ACA     PUSH EAX
    7C825ACB     PUSH -1
    7C825ACD     CALL DWORD PTR DS:[<&ntdll.NtFreeVirtual>  ntdll.ZwFreeVirtualMemory
    7C825AD3     MOV EAX,DWORD PTR FS:[18]        ;_TEB Struct
    7C825AD9     MOV EAX,DWORD PTR DS:[EAX+30]    ;points to _PEB Struct
    7C825ADC     PUSH ESI                         ;lpFiber
    7C825ADD     PUSH 0                           ;0x00000000
    7C825ADF     PUSH DWORD PTR DS:[EAX+18]       ;PEB.ProcessHeap
    7C825AE2     CALL DWORD PTR DS:[<&ntdll.RtlFreeHeap>] ; ntdll.RtlFreeHeap
    7C825AE8     POP ESI
    7C825AE9     LEAVE
    7C825AEA     RETN 4

    In the first part of DeleteFiber is retrived the _TEB structure and specifically a member of _TIB structure located at 10h

    0:003> dt nt!_TEB -b
    +0x000 NtTib : _NT_TIB
    +0x000 ExceptionList : Ptr32
    +0x00c SubSystemTib : Ptr32
    +0x010 FiberData : Ptr32

    and next if FiberData is equal to our Fiber's Address it means that Fiber is suicinding itself and system calls ExitThread(), next we can notice a NtFreeVirtualMemory call with the following parameters:

    NtFreeVirtualMemory(NtCurrentProcess(), &pStackAllocBase,&nSize,MEM_RELEASE);
    The system deallocates the used stack and finally calls RtlFreeHeap in this manner:

    RtlFreeHeap(GetProcessHeap(), 0, lpFiber);
    This last call clarifies totally the presence of ERROR_INVALID_PARAMETER because has we have seen DeleteFiber is directly correlated with Heap, and Heap Memory presents a set of Flags that characterize the Heap itself.
    These Flags differs in case the process IS debugged or NOT, so we can suppose that these flags are created when the exe itself is executed, in other words at Process Creation Time. Under Windows NT processes are created through PspUserThreadStartup and inside it we can found LdrInitializeThunk, that as Russinovich sais The LdrInitializeThunk routine initializes the loader, heap manager, NLS tables, thread-local storage (TLS) array, and critical section structures. By going more deep we can see that there is a specific function that fill the PEB Struct of the new process MmCreatePeb(), PEB is important because between his various fields are stored Heap Flags of our process. I'm talking about NtGlobalFlag, for a debugged process these flags are:

    #define FLG_HEAP_ENABLE_TAIL_CHECK 0x00000010
    #define FLG_HEAP_ENABLE_FREE_CHECK 0x00000020
    #define FLG_HEAP_VALIDATE_PARAMETERS 0x00000040

    Now if a process has these flags enabled ( HeapDebug ) RtlFreeHeap will fail the Heap freeing and this error will be propagated to DeleteFiber() that will exit with an ERROR_INVALID_PARAMETER.

    Anti Anti-Debug

    Due to the fact that the Heap Validation is accomplished at Processs Creation Time, one countermeasure against Anti-Debug will be to attach the debugger after that the process is created.
    If you are using WinDbg could be used the HeapDebug option ( -hd )
    Between the function involved in process creation we have also LdrQueryImageFileExecutionOptions that mantains trace of IFEO ( Image File Execution Options structure) this struct is located into Registry under the path [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\]
    The various possible values are:
    GlobalFlag can be used to modify NtGlobalFlag, so if you set this key entry to NULL, Heap of the debugged program will looks as an undebugged one, read this as an Anti-Anti Debug Trick .

    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Target.exe]

    Giuseppe 'Evilcry' Bonfa'
  15. Some words on how to decrypt trojan Ascesso

    This post is a little bit long, for a better reading you can download the pdf version here:

    Roaming around Symantec web pages I stumbled on a review of a trojan named Ascesso. The malware does a lot of things that are described inside the “Technical details” section. I decided to give it a try just because it’s interesting to read what a malware does, but it’s much more funny when you play with it! In this blog entry I won’t talk about what the malware does, but I’ll write something about the way I used to obtain a readable dead list inside Ida. One of the next blog entry could be focused on the analysis of the malware, don’t know.

    The file I’m going to analyze is named asc3550.sys, md5=BBEB49A32417226CABED3E104A9C94B5.
    The malware is crypted, I think it’s a home made protection. If you load the file in Ida you are not able to see too much, almost all the code has been crypted. To view the uncrypted malware you have two options: you can run the driver dumping the memory image using a ring0 dumper (i.e. softice+icedump), or you can use Ida trying to convert the initial output into something really closer to the original driver. Generally, I like to work on a simple dump of the packed/crypted file, but with a driver I prefer to work on a perfect file. With a simple dump of the image you’ll have to deal with instructions like:
    .text:0040381B   call  dword ptr ds:0F77B3664h
    .text:004028F9   mov   dword ptr [edi], 0F77AF000h
    .text:0040294E   movzx eax, byte ptr ds:0F77B36D2h
    It’s hard to say what’s going on when you have unknown addresses in front of you. I think you’ll prefer to look at something like:
    .text:0040381B   call  ds:_ExAllocatePoolWithTag
    .text:004028F9   mov   dword ptr [edi], offset __ImageBase
    .text:0040294E   movzx eax, ds:byte_4046D2
    This is what I’m going to do.

    Initial decryption
    When you load the file in Ida the decryption routine is the only visible code:
    00400240 000    jmp  short loc_400257   ; Entry point
    00400242     sub_400242 proc near
    00400242     arg_4= dword ptr  8
    00400242 000    lea  edx, [esp+arg_4]
    00400246 000    mov  edx, [edx]
    00400248 000    mov  edx, [edx+0Ch]
    0040024B 000    add  edx, 9540h
    00400251 000    mov  eax, 9AEDh
    00400256 000    retn
    00400256     sub_400242 endp
    00400257     loc_400257:
    00400257 000    call sub_400242
    0040025C 000    pusha
    0040025D 020    push 55Ch
    00400262 024    pop  ecx
    00400263     Decrypt_1:
    00400263 020    mov  eax, [edx]        ; Current dword to decrypt
    00400265 020    sub  eax, 0FA598390h   ; Decryption: sub operation
    0040026A 020    mov  [edx], eax        ; Save the decrypted dword
    0040026C 020    lea  edx, [edx+4]      ; Next dword to decrypt
    0040026F 020    sub  ecx, 4
    00400272 020    test ecx, ecx
    00400274 020    jnz  short Decrypt_1
    00400276 020    popa
    00400277 000    mov  ecx, 9B29h
    0040027C 000    add  edx, 2
    0040027F 000    add  edx, 6
    00400282 000    jmp  edx
    These are the starting instructions. Reading through various forums I had the impression that most of the people have some problems trying to anaylize this kind of snippets. It’s pretty obvious what the snippet does, it’s a simple decryption routine consisting in a sub operation. The main problem is: which part of code will be decrypted? Everything depends on value stored inside edx register, which is obtained by the instructions inside the call 400242:
    00400242 lea  edx, [esp+8]     ; stack value
    00400246 mov  edx, [edx]       ; edx is an address !?!
    00400248 mov  edx, [edx+0Ch]   ; edx points to a structure !?!
    0040024B add  edx, 9540h       ; add operation
    How to know the exact value pointed by [esp+8]? Taking in mind that the file I’m analyzing is a .sys file you can get the value inside the stack with a simple deducting reasoning.

    The first driver instruction is the one at 400240, but who brings me there? I mean, there should be an instruction which is executed before the one at 400240. The instruction is a call and it’s somewhere inside IopLoadDriver function (in ntoskrnl.exe):
    PAGE:004DCFE2 020 push [ebp+68h+PreviousMode]   ; PUNICODE_STRING RegistryPath
    PAGE:004DCFE5 024 push edi                      ; PDRIVER_OBJECT pDriverObject
    PAGE:004DCFE6 028 call dword ptr [edi+2Ch]      ; Call DriverEntry
    [edi+2C] points to DriverInit, 400240 in this particular case. Look at the last parameter (pDriverObject), it’s really important. You have to concentrate on the stack only, when you are at the first driver instruction you’ll have something like:
    esp+00h: IopLoadDriver_return_address
    esp+04h: pDriverObject
    esp+08h: RegistryPath
    esp+0Ch: …
    Here’s how the stack looks like when you are inside the “call sub_400242″, at address 400242:
    esp+00h: call_400242_return_address
    esp+04h: IopLoadDriver_return_address
    esp+08h: pDriverObject
    esp+0Ch: RegistryPath
    esp+10h: …
    Now it’s pretty easy to retrieve the starting value of edx:
    00400242 lea  edx, [esp+8]        ; edx = pDriverObject
    00400246 mov  edx, [edx]          ; edx points to the first byte of DRIVER_OBJECT structure
    00400248 mov  edx, [edx+0Ch]      ; edx = DRIVER_OBJECT+0Ch
    0040024B add  edx, 9540h          ; edx = edx + 0×9540
    Just a little more step and you’ll have the value we are searching for. Look a the definition of the DRIVER_OBJECT structure, taken from ntddk.h:
    typedef struct _DRIVER_OBJECT {
    CSHORT Type;                   // +0×00
    CSHORT Size;                   // +0×02
    PDEVICE_OBJECT DeviceObject;   // +0×04
    ULONG Flags;                   // +0×08
    PVOID DriverStart;             // +0×0C
    ULONG DriverSize;              // +0×10
    PVOID DriverSection;           // +0×14
    PDRIVER_EXTENSION DriverExtension;   // +0×18
    UNICODE_STRING DriverName;           // +0×1C
    PUNICODE_STRING HardwareDatabase;    // +0×24
    PFAST_IO_DISPATCH FastIoDispatch;    // +0×28
    PDRIVER_INITIALIZE DriverInit;       // +0×2C
    PDRIVER_STARTIO DriverStartIo;       // +0×30
    PDRIVER_UNLOAD DriverUnload;         // +0×34
    PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];   // +0×38
    DRIVER_OBJECT+0Ch is DriverStart, the memory address that points to the first byte of the driver. I don’t have the possibility to know the exact value stored inside DriverStart field, but for a static analysis you can suppose that the address is the ImageBase: 0×400000. It comes out that the edx value we want is: 0×400000+0×9540 = 0×409540

    It’s time to decrypt the bytes using this simple idc script:
     static main()
       auto CurrentAddress, i;
       CurrentAddress = 0×409540;
          PatchDword(CurrentAddress, (Dword(CurrentAddress) - 0xFA598390));
          CurrentAddress = CurrentAddress + 4;
       Message(”\nDecryption done, last address: %X”, CurrentAddress);
    I inserted the Message function just because I wanted to see the first non-decrypted address: 0×409A9C; you can remove the function, if you prefer.
    Ok, now that the decryption is complete I have to look at the decrypted code. The last instruction of the initial decryption routine will bring me directly at a fresh decrypted instruction, which is the next instruction to be executed?
    00400276 popa              ; edx = 0×409540
    00400277 mov  ecx, 9B29h   ; ecx = 0×9B29
    0040027C add  edx, 2       ; edx = 0×409540 + 2 = 0×409542
    0040027F add  edx, 6       ; edx = 0×409542 + 6 = 0×409548
    00400282 jmp  edx          ; jmp 0×409548
    The decrypted code is a small routine, all the other bytes of the file are still crypted; maybe I have to deal with some more layers. The decrypted code contains an initializations part, some calls end a final jmp instruction.


    It’s pretty easy to understand the initialization code. I won’t attach any snippet,it’s only a sequence of mov/add/lea instructions used to retrieve/store some special values that are used later.
    At the end of the initialization part there’s a piece of code which is used to move 0×44 bytes:
    .reloc:00409592 add  edi, [ebp+401BF4h]   ; edi = 400240
    .reloc:00409598 lea  esi, [ebp+401D52h]   ; esi = 409A48
    .reloc:0040959E mov  ecx, 44h
    .reloc:004095A3 rep movsb
    Do you know what 400240 is? It’s the entry point of the file. It’s something to remember for the next decryption script.

    Sections decryption
    The first interesting piece of code is located inside a call at 0×4095C1, before studying the call I prefer to take a look at the parameters:
    .reloc:004095B1 push dword ptr [ebp+401BF8h]   ; ebp+401BF8 and ebp+401BEC were setted
    .reloc:004095B7 push dword ptr [ebp+401BECh]   ; up in the initialization part
    .reloc:004095BD push 1
    .reloc:004095BF push eax
    .reloc:004095C0 push ebx
    .reloc:004095C1 call Decrypt_First_5_Sections
    I can’t get any clue from the parameters, I can’t say nothing else without spying the code. After a little investigation over the previous instructions I discover what the parameters are:
    - ebx = DriverStart
    - eax = 0×409A38
    - 1
    - dword ptr [ebp+401BECh] = 0×9540
    - dword ptr [ebp+401BF8h] = 0×8FA0

    Just wait some minutes and I’ll tell you everything about these parameters.
    As you can see I renamed the call, the name suggests ...

    Updated October 4th, 2007 at 13:09 by ZaiRoN

Page 3 of 5 FirstFirst 12345 LastLast