All Blog Entries

  1. The secret project finally revealed...

    After spending most of my available spare time for the majority of this past year on a secret project which I've hoped will be of great benefit for the entire reversing community, I'm finally today quite proud to be able to present to you all:

    The Collaborative RCE Tool Library

    http://www.woodmann.com/collaborative/tools

    For more introductory information about this project and what it's for, please see the following forum thread:

    http://www.woodmann.com/forum/showthread.php?t=11097

    And for further discussions about it, this is its official forum thread:

    http://www.woodmann.com/forum/showthread.php?t=11098

    I hope you will all enjoy it, I sure know I will!
    Categories
    Uncategorized
  2. Site Relaunch

    Hi,

    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

    www.reverse-engineering.info
    www.woodmann.com/yates

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

    Merry Christmas,

    Rob.
    Categories
    Uncategorized
  3. Beware of int 2c instruction

    In the last days I played a little with Win32.Virtob virus, thanks to Kayaker for passing it out to me. It’s a nice virus with some interesting tricks. You can read a detailed analysis made by Kayaker from his recent blog entries.
    In this post I’m not going to talk about the malware itself, I simply focus my attention on an single instruction: int 2c. The instruction is located in the beginning of the virus and I spent some time on it trying to answer Kayaker’s question: is “int 2c” used as an antidebug trick? I don’t have an answer for the question, but after some tries I came up with something that can be interesting.

    Int2c
    execution changes the content of some registers, but one of them (in particular edx) is always changed in the same way. edx contains the address of the instruction that follows the int 2c instruction.
    Code:
    100: mov edx, 80   <– edx = 0×80
    105: int 2c   <– it changes edx value
    107: xor eax, eax   <– here: edx = 0×107
    Pretty weird. To know why you have to look at ntoskrnl code (starting from KiSetLowWaitHighThread), it’s pretty easy to find out why. Here’s the last part of the int2c code:
    Code:
    804d4f95 pop     edx   <-- edx is changed here
    804d4f96 add     esp,8
    804d4f99 pop     ecx
    804d4f9a sti
    804d4f9b sysexit
    Sysexit is the key of this snippet. The function is used when there’s a transition from ring0 to ring3 code. ring3.eip is updated with ring0.edx value. That’s why edx contains the magic value, if you want to go back into ring3 world you have to put the return address into edx.
    Is this fact important? Not really, per se. There’s a interesting use of this behaviour btw, infact it could be used inside an obfuscation engine or as an anti Ollydbg trick.

    Look at this simple and stupid sample I wrote (attached at the end of the post):
    Code:
    00401000 LEA EDX,DWORD PTR DS:[403000]      ; 403000 -> "easy sample"
    00401006 PUSH EDX
    00401007 INT 2C
    00401009 PUSH 0                             ; Style = MB_OK|MB_APPLMODAL
    0040100B INT 2C
    0040100D SUB BYTE PTR DS:[EDX+6],9          ; 403006 = ‘X’
    00401011 LEA EAX,DWORD PTR DS:[403015]      ; 403015 -> “I’m the caption”
    00401017 PUSH EAX                           ; Title_1: “I’m the caption”
    00401018 INT 2C
    0040101A XOR BYTE PTR DS:[EDX+6],1D         ; 403006 = ‘E’
    0040101E LEA EAX,DWORD PTR DS:[403038]      ; 403038 -> “I’m the text”
    00401024 PUSH EAX                           ; Text_1: “I’m the text”
    00401025 INT 2C
    00401027 PUSH 0                             ; hOwner = NULL
    00401029 INT 2C
    0040102B CALL <JMP.&user32.MessageBoxA>     ; MessageBoxA, display the 1° message box
    00401030 POP EDX                            ; edx -> “easy sEmple”
    00401031 PUSH 0                             ; Style = MB_OK|MB_APPLMODAL
    00401033 PUSH msgbox.0040300C               ; Title_2: “Int2c…”
    00401038 PUSH EDX                           ; Text_2: “easy sEmple” (”sEmple” and not “sample”)
    00401039 PUSH 0                             ; hOwner = NULL
    0040103B CALL <JMP.&user32.MessageBoxA>     ; MessageBoxA, display the 2° message box
    00401040 PUSH 0                             ; ExitCode = 0
    00401042 CALL <JMP.&kernel32.ExitProcess>   ; ExitProcess
    This is the static analysis of the snippet above, it’s not right! Try running the attached exe (I can assure you it’s not dangerous) and you’ll see the real behaviour of this piece of code. It displays two message boxes with the real messages, the first one with:
    caption: “Int2c…”
    text: “Obfusction sample”
    and the second with:
    caption: “Int 2c…”
    text: “easy sample” (it’s not “sEmple”)

    Why? Well, it’s pretty simple:
    Code:
    0040100B  CD 2C          INT 2C                          ; int2c changes edx value
    0040100D  806A 06 09     SUB BYTE PTR DS:[EDX+6],9       ; edx = 40100D, it changes 403015 into 40300C
    00401011  8D05 15304000  LEA EAX,DWORD PTR DS:[403015]   ; eax = 40300C, 40300C -> “Int2c…”
    Execution of int 2c changes edx value, and if you don’t know anything about it you’ll have a wrong static analysis. It’s a simple code obfuscation, but you have to take care of it for sure.

    Now, try loading the attached exe file into Ollydbg. These are the results I got from my tests based on an XP sp1 and sp2 machines.

    Ollydbg and XP sp1
    The file runs fine when you launch it with F9 key, it shows the real messages.
    The problems arise when you step through the code with “step into”(F7) or “step over”(F8) modes. No matter if you are stepping with F7 or F8, executing an int 2c instruction the debugger won’t break unless you have inserted a bpx onto one of the next instructions. A perfect trick for those who don’t know how to deal with it, you step the instruction and the malware performs all his nasty operations…

    Ollydbg and XP sp2
    The file runs fine when you launch it with F9 key, it shows the real messages.
    F7 and F8 modes have the same behaviour, Ollydbg stops at the second instruction after “int 2c“; the problem is that edx value is not updated with the correct address value. Here’s what happen:
    Code:
    00401006 PUSH EDX                    ; edx = 403000
    00401007 INT 2C                      ; F7 or F8 here and Ollydbg
    00401009 PUSH 0                      ; will break at 40100B
    0040100B INT 2C                      ; F7 or F8 here and Ollydbg will
    0040100D SUB BYTE PTR DS:[EDX+6],9   ; break here due to the exception:
    ; “Access violation when writing to [00000005]”

    The exception occours because (at 40100D) edx value is 0xFFFFFFFF. edx value was changed by “int 2c” at 40100B.
    The only way to obtain a correct edx value is to use F9 setting a bpx at 40100D.

    I tried the same exe with Ida debugger on a XP sp2 machine. You can step using F8 without problem, but not with F7 because you’ll get the same access violation.

    I think it’s definitely something to take care of, what do you think?

    (File available here: http://www.box.net/shared/static/zebzmt8srt.zip)
    Categories
    Uncategorized
  4. IDC scripting a Win32.Virut variant - Part 2

    This post continues Part 1, which should be read first for reference.

    Some points of interest about the viral code itself:

    • There is a small RDTSC timing check at the start. If the difference between 2 RDTSC calls is greater than 0x100 then it's determined that you're in a VM or single step tracing the code (or have only 4K of memory maybe!). In that case the virus doesn't infect but instead returns to the default address of 0x40101D and only tries to connect to the irc server.

      Doing a little test I found that 2 RDTSC calls would return a difference of between 1000-1500 ticks under VMWare, but only 50 ticks under a real system. Not a sophisticated VM test, but it seems to work.

    • There is also apparently a Redpill type VM check which I found crashes under VMWare.

      Code:
      :0040323A RedPill:      ; CODE XREF: Main+2
      :0040323A       push    eax
      :0040323B       sidt    qword ptr [esp-2]
      :00403240       pop     eax
      :00403241       mov     eax, [eax+6]    ; invalid pointer, crashes under VMWare
      :00403241                               ; buggy code?!
      :00403244       shl     eax, 10h
      :00403247       jns     short Force_RDTSC_test_to_fail
    • The virus is Win9x/Me compatible. If the OS is Win2K or greater it hooks NtCreateFile / NtOpenFile. If Win9x, it hooks VWIN32_Int21Dispatch and monitors for the MS-DOS LFN (long file name) service 0x716C, which is used for open/create. The Win9x related stuff is "old school" and has been documented before. If interested see:

      The VxDCall backdoor http://vx.netlux.org/lib/vgy06.html
      VIRUS ANALYSIS 2 http://peterszor.com/hps.pdf

    • The virus copies itself to the last section of a file it infects, but the initial seed value for the Xor decryption routine is different for every infected file (uses an RDTSC randomization), showing its polymorphic nature. After copying itself from running memory into the file, the main Decrypt function is called once again, but this time it's encrypting itself in the file, the XOR routine being reversible.

    • After determining the system offsets for the Nt calls it hooks, the virus creates a section, maps itself into it, then immediately continues execution from this high memory mapping address. All further execution is run from this memory mapped image. This makes it a little more difficult when live tracing and comparing addresses to the disassembly, but the jump to high memory makes a great breakpoint when you get deeper into the live analysis.

      .data:004035FE lea eax, dword_403606
      .data:00403604 jmp eax
      .data:00403606 ... ; this is now running from high mem



    • One interesting (though not original) thing the virus does is how it disables Windows File Protection (WFP) so it can infect any file in any directory without being subverted.

      Immediately after beginning execution in the high memory mapped section that I just mentioned, it calls NtAdjustPrivilegesToken with SeDebugPrivilege privilege so it is able to call CreateRemoteThread() in the Winlogon process.

      How to obtain a handle to any process with SeDebugPrivilege
      http://support.microsoft.com/kb/131065

      Using a CreateToolhelp32Snapshot/Process32Next loop, it scans for the 4th process returned, or Winlogon. Then it hooks the 4 Nt calls within the winlogon address context by overwriting the Service Id of the relevant Zw ntdll KiFastSystemCall with a detour to its own hook routine (which is mapped into winlogon memory space).

      Once this is done it calls CreateRemoteThread followed by a short Sleep routine to let the remote thread execute within winlogon context. After the Sleep nap, the CreateToolhelp32Snapshot loop continues and hooks the 4 Nt calls in every other active process.

      The aforementioned CreateRemoteThread winlogon thread does a number of things besides disabling WFP. It sets up the Win9x/Me VxDCall file hook if applicable, writes the irc sites IP address to the Windows hosts file, accesses the registry, creates some Events, creates a couple more threads, one of which maps out ntoskrnl and the KeServiceDescriptorTable, tries to connect to the internet, etc.


      WFP is disabled by patching in a call to ExitThread immediately after a NtWaitForMultipleObjects call in an sfc.os.dll function called SfcWatchProtectedDirectoriesWorkerThread. The function name pretty much describes what it does, it's a worker thread which continually monitors for file changes from a protected dll list. After patching SfcWatchProtectedDirectoriesWorkerThread the virus calls SfcTerminateWatcherThread. (IDA + symbols is a wonderful thing )

      Here is what the function looks like in code:

      Code:
      // The search pattern in sfc.os.dll
      
      :00403CE4          Pattern_SFC_OS_DLL:    ; DATA XREF: Disable_WFP+F
      :00403CE4 6A 01       push    1
      :00403CE6 6A 01       push    1
      :00403CE8 FF 33       push    dword ptr [ebx]
      :00403CEA FF 73 04    push    dword ptr [ebx+4]
      :00403CEA          ; -----------------------------------------------
                            // part of call ds:NtWaitForMultipleObjects
      :00403CED FF 15       dw 15FFh   
      
      
      
      :00403CEF Disable_WFP     proc near
      
      // EAX = base address of sfc.os.dll returned from GetModuleHandleA
      
      :00403CEF       test    eax, eax
      :00403CF1       jz      short locret_403CE3
      :00403CF3       push    0Bh
      :00403CF8       mov     edx, eax
      :00403CFA       pop     ebx
      :00403CFB       add     edx, [eax+IMAGE_DOS_HEADER.e_lfanew]
      :00403CFE       lea     esi, Pattern_SFC_OS_DLL
            
                              // SectionTable.PointerToRawData .text section
      :00403D04       mov     edi, [edx+10Ch]
                              // SectionTable.SizeOfRawData .text section
      :00403D0A       mov     ecx, [edx+108h]
             
      :00403D10       add     edi, eax
      :00403D12       sub     ecx, ebx
      :00403D14
      :00403D14 Find_Pattern:           ; CODE XREF: Disable_WFP+2E
      :00403D14       pusha
      :00403D15       mov     ecx, ebx
      :00403D17       repe cmpsb
      :00403D19       popa
      :00403D1A       jz      short loc_403D21
      :00403D1C       inc     edi
      :00403D1D       loop    Find_Pattern
      :00403D1F       jmp     short locret_403CE3
      :00403D21 ; ----------------------------------------------------
      :00403D21
      :00403D21 loc_403D21:             ; CODE XREF: Disable_WFP+2B
      :00403D21       add     edi, 0Fh
      :00403D24       push    edi
      :00403D25       mov     edx, esp
      :00403D27       push    ebx
      :00403D28       mov     ecx, esp
      :00403D2A       push    eax
      :00403D2B       push    esp             ; OldProtect
      :00403D2C       push    40h             ; Protect
      :00403D2E       push    ecx             ; RegionSize
      :00403D2F       push    edx             ; BaseAddress
      :00403D30       push    0FFFFFFFFh      ; hProcess
      :00403D32       call    NtProtectVirtualMemory
      :00403D38       add     esp, 0Ch
      :00403D3B       mov     edx, ExitThread
      :00403D41       sub     edx, edi
      :00403D43       sub     edx, 7
      
      // Patch in ExitThread call immediately after
      // NtWaitForMultipleObjects in sfc.os function
      // SfcWatchProtectedDirectoriesWorkerThread
      
      // patch in push eax opcodes (6A00) + Call near, relative opcode (E8)
      :00403D46       mov     dword ptr [edi], 0E8006Ah  
            
      // patch in ExitThread displacement
      :00403D4C       mov     [edi+3], edx
                
      :00403D4F       retn
      :00403D4F Disable_WFP     endp ;
      Once I figured out what the code was doing I was able to do a search and found that the entire routine for disabling WFP was ripped from here:

      Win2k.SFPDisable
      http://www.hackemate.com.ar/ezines/29a/29a-6/Articles/29A-6.001



    • And finally, and congratulations if you're still reading this, there is a mysterious Int 0x2C interrupt call at the start of the program. This call is the main reason this virus held my interest for so long and is ultimately the genesis of this article. I was hoping a full analysis of the program would point out its purpose. Alas, I'm still as clueless as when I started.


      Therefore I open up to speculation (or reason or knowledge), the true function of this Int2C call, if there is one, to you Gentle Reader (may Asimov forgive me).


      Here is the start of the code once again showing the important bits. I've tried to outline the "normal" path of infection by highlighting in Blue. Under any condition that I can see, Int2C will always return STATUS_NO_EVENT_PAIR, so that particular path of execution is fixed.

      The question is then. is this just quirky code to confuse us, or can an Int2C call have a real purpose in Ring3 under certain conditions?


      Code:
      :00403200 start           proc near 
      :00403200                 cld
      :00403201                 call    Main
      :00403201 start           endp
      :00403201
      
      :0040321F popebp_ret:
      :0040321F                 pop     ebp
      :00403220                 retn
      .
      :00403221 Force_RDTSC_test_to_fail:
      :00403221                 push    ebp
      :00403222                 mov     eax, 8000h
      :00403227                 xor     ecx, ecx
      :00403229                 jmp     short loc_403255
    ...
    Categories
    Uncategorized
  5. IDC scripting a Win32.Virut variant - Part 1

    I had started live tracing this piece of malware when I realized it was a prime candidate for some IDA idc scripting. There are a few things about the program which makes static analysis difficult.

    1. It's encrypted. It's a rather simple encryption however which is easily scripted out.
    2. The code is primarily executed in the .data section and there are many inline character strings and non-standard code instructions which prevent IDA from getting an accurate disassembly.
    3. Variable pointers and import calls are referenced as EBP offsets, so IDA can't recognize absolute addresses to create the proper Xrefs, autogeneration and all the other wonderful analysis it normally performs.
    4. Imports are determined dynamically through GetProcAddress, so until we define them IDA can't recognize them.


    Let's address each of these problems through a bit of idc scripting and static analysis to supplement our live tracing. In Part 2 I'll mention a few points about the viral code itself.

    I've included several files in the attachment, the idc scripts, a header file prototyping some functions and structures not included in the internal IDA definitions. As well there is as an IDB file in IDA 4.9 freeware version format which is fully commented with all functions and variables defined (or at least named, this is meant to be a "working" disassembly for further analysis, not necessarily a definitive treatise). The IDB file can be opened in any IDA version 4.9 and above.

    Also included is of course the virus, or else what fun would this be? The win32_virut.exe file has been renamed with a .VXE extension and zip password protected with the password malware. It is quite an infectious file, but it readily detects a normal virtual machine sandbox and won't infect under those conditions. You actually have to force the code to decrypt its payload under a VM. Also, the remote site it tries to connect to has been closed for Terms Of Agreement violations (ya think?), so no live connection is ever made.

    You may find it easier to read the idc scripts by downloading the originals or by reading this post in the Blogs Forum (follow the link under 'Post or View Comments' at the bottom of this blog).


    A brief description of the virus family from
    http://www.bitdefender.com/VIRUS-1000163-en--Win32.Virtob

    This virus is a polymorphic, memory-resident file-infector, with backdoor behaviour. Once executed, it injects itself into WINLOGON, creates a new thread in that process, and passes the execution control to the host file.

    It also hooks the following functions in each running process (in NTDLL module):
    NtCreateFile, NtOpenFile, NtCreateProcess, NtCreateProcessEx
    so that every time an infected process calls one of these functions, the execution is passed to the virus, which infects the accessed file, and then returns the control to the original function.

    It infects EXE and SCR files, using different infection techniques:
    Appending to the last section of the victim, and setting the Entry Point directly to the viral code. (our variant)

    The virus is able to avoid emulators and virtual machines. To ensure there's only one instance of it running in the system, it creates an event with one of the following names:
    VT_3, VT_4, VevT, Vx_4

    It tries to connect to some IRC server, and join a certain channel. Once it joins the channel, it waits for commands that instruct it to download several files from Internet, and then execute them. The IRC server can be:
    proxim.ntkrnlpa.info (our variant, site no longer active)
    Much of what is written above can be figured out by live tracing the malware and eventually letting it infect our sandbox. But let's see what damage we can do to it before it does damage to us..


    Step 1: Decrypt

    Here is the Entry Point of the virus, which is in the .data section:
    Code:
    :00403200                 cld
    :00403201                 call    loc_40322E
    :00403206                 push    ebx
    Take note that the return address of the Call pushed onto the stack will be 0x403206. Trace into the Call and after a bit of preliminary code we reach here:

    Code:
    :00403257  mov     ebp, [esp+4]
        // call return of 0x403206 placed in ebp
     
    :0040325B  sub     dword ptr [esp+4], 21E9h
        // new return address of (0x403206 - 0x21E9) = 0x40101D placed on stack
    ...
    :0040326A  sub     ebp, 301006h
    // ebp offset becomes (0x403206 - 0x301006) = 0x102200
    :00403270  lea     eax, [ebp+301082h]
    // eax = (0x102200 + 0x301082) = 0x403282
    // this is the starting address of the encrypted code
    :00403276  mov     dx, [eax-65h]
    // word pointer at 0x40321D is a decryption seed value:  db 8Eh, 0C8h
    :0040327D  call    sub_403206      // Decryption routine
    // the code from here on down is all encrypted
    :00403282  db      65h
    :00403282  enter   0BDDh, 0C1h
    :00403287  push    ss
    The fact that none of the code from address 0x403282 onwards doesn't make much sense indicates that Call sub_403206 is a decryption routine. Let's take a look at that call:

    Code:
    :00403206 Decrypt         proc near               ; CODE XREF: :0040327D
    :00403206                 push    ebx
    :00403207                 mov     ecx, 0DA5h
    :0040320C                 mov     ebx, edx
    :0040320E
    :0040320E loc_40320E:                             ; CODE XREF: Decrypt+13
    :0040320E                 xor     [eax], dx
    :00403211                 lea     eax, [eax+2]
    :00403214                 xchg    dl, dh
    :00403216                 lea     edx, [ebx+edx]
    :00403219                 loop    loc_40320E
    :0040321B                 pop     ebx
    :0040321C                 retn
    :0040321C Decrypt         endp
    :0040321C
    :0040321C ; ---------------------------------------------------------------
    :0040321D Initial_Decrypt_Seed db 8Eh, 0C8h
    :0040321F; ----------------------------------------------------------------
    A simple XOR loop decryption where the xor value is modified on each iteration by the XCHG instruction. ECX is a counter decremented by the LOOP opcode. The initial decryption seed value is the db 8Eh, 0C8h we discovered above.

    Armed with this small bit of analysis we can create the following idc script for decrypting.

    PHP Code:
    #include <idc.idc>
    // Step 1: idc to decrypt section between .data:0x403282 and .data:0x404DCC    
     
    // performs the equivalent asm function (xchg dl, dh)
    #define    bswap16(x)                    \
        
    ((((x) & 0xff00) >> 8) |        \
         (((
    x) & 0x00ff) << 8))
     
    static 
    main()
    {
        
    auto startdecryptsizeenddecryptseedeadecryptwordx;
     
     
        
    // starting values determined from decrypt function
     
        
    startdecrypt 0x403282;
        
    size 0x0DA5 2;                          // word size replacement
        
    enddecrypt = (startdecrypt size);         // = 0x404DCC
        
    seed 0xC88E;
     
        
    ea startdecrypt;
        
    decryptword seed;
     
        
    Message("\nDecrypting... \n");
        while (
    ea enddecrypt)
        {
                                                    
    // (xor [eax], dx)
            
    Word(ea);                               // fetch the word
            
    = (decryptword);                      // decrypt it
            
    PatchWord(eax);                           // put it back            
            
    decryptword bswap16(decryptword);     // xchg dl, dh
            
    decryptword decryptword seed;       // lea edx, [ebx+edx]
     
            
    ea ea 2;    
        }
     
        
    // Let's try to get IDA to reanalyze the code
        
    MakeUnknown (startdecryptsize1);
        
    AnalyzeArea (startdecryptenddecrypt);
        
    Message("...Done \n");

    After running this script you MUST go through the decrypted section and manually resolve the embedded string pointers with the IDA A(scii) command and any unrecognized or incorrect disassembly with the C(ode) command. This is a necessary step for the subsequent IDC scripts to work properly!

    You will find a lot of things like the following, which you need to make sure is correctly resolved. By itself IDA won't properly disassemble the code.

    Code:
    :004032D8 E8 0D     call    loc_4032EA
    :004032D8                   ; --------------------------------------------
    :004032DD 47 65+ aGetlasterror   db 'GetLastError',0 // LPCSTR lpProcName
    :004032EA                   ; --------------------------------------------
    :004032EA
    :004032EA        loc_4032EA:       ; CODE XREF: :004032D8
    :004032EA 03 F3     add     esi, ebx
    :004032EC 53        push    ebx     // HMODULE hModule
    :004032ED FF D6     call    esi     // GetProcAddress
    Notice the neat little trick in the above code of how the second parameter of GetProcAddress is automatically pushed onto the stack by effectively being the return address of Call loc_4032EA, which jumps over the string. This type of thing is repeated throughout the program.

    Chances are you won't get every bit of disassembly and ascii string identified correctly the first time through a manual fixup, but after applying ...
    Categories
    Uncategorized
    Attached Thumbnails Attached Files
  6. New face and new concept for the Reverse Code Engineering Video Portal

    As promised, the site has been improved greatly.
    http://video.reverse-engineering.net

    We are now using a multi-lingual Video Gallery interface with many useful features.

    Everybody can now publish their own RCE-related videos (not porn!) in their personal gallery by manual upload or direct URL download by the server.
    So many good videos disappear every day from RapidShare-like hosting.

    The most interesting ones will be moved to the main sections for more visibility.

    For those who don't like watching videos online or downloading many separate files, it is possible to create your own custom downloadable ZIP package (batch-download) by adding videos to your Favorites folder.

    We added more than 100 videos to the local database, including:

    40 videos from the Lena series
    43 conference videos from Recon 05 and 06 (including Woodmann, Fravia and Zero)
    7 buffer overflow videos, some using olly
    3 video solutions from crackmes.de
    and many more, all in one place.

    As if that wasn't enough, 3 new videos in my IDA series:

    6. TLS-CallBacks and preventing debugger detection with IDA
    7. Unwrapping a Flash Video Executable (exe2swf)
    8. Stop fishing and start keygenning.

    The last one is an analysis of a crackme using anti-debugging techniques with IDA.

    I hope we will receive some contributions soon.
    Categories
    Uncategorized
  7. Future occupation: Archeological reverser?

    A nice little story on the source code reversing of a highly compact binary code of a program written for an ancient processor:

    http://hardware.slashdot.org/article.pl?sid=07/11/15/1818248
    Categories
    Uncategorized
  8. xml embed references. halp! :(

    Hi.

    Could anyone please offer any tips/pointers/ideas on how to optimize the following:

    For each element in document, that has a href attribute and no children elements and no text children nodes,
    find the element with id = the value of that href attribute and move all children elements and attributes (except id) to the referencing element, and remove the referenced element.

    The current implementation takes 0,09 sec per root level detached element on a 10MB xml document, which amounts to about 3 minutes.
    That is bearable but the situation is hopeless with more elements ...

    Code:
    protected static void EmbedRefs(ref XmlNode n, ref XmlNode container)
    {
    	int i = 0;
    	XmlNodeList detachedChildren = n.SelectNodes("child::*[@href and not(text())]");
    	foreach (XmlNode child in detachedChildren)
    	{
    		string href = child.Attributes["href"].Value.Substring(1);
    		XmlNode referee = container.SelectSingleNode("child::*[@id='" + href + "']");
    
    		EmbedRefs(ref referee, ref container);
    
    		child.Attributes.RemoveNamedItem("href");
    
    		while (referee.FirstChild != null)
    		{
    			XmlNode fc = referee.FirstChild;
    			referee.RemoveChild(fc);
    			child.AppendChild(fc);
    		}
    
    		foreach (XmlAttribute attr in referee.Attributes)
    		{
    			if (attr.LocalName == "id")
    				continue;
    
    			child.Attributes.Append((XmlAttribute)attr.Clone());
    		}
    
    		referee.ParentNode.RemoveChild(referee);
    	}			
    }
    thx to anyone who takes a look
    Categories
    Uncategorized
  9. Video #5 is up.

    New addition to the Reverse Code Engineering Community Forum video tutorial website:
    http://video.reverse-engineering.net

    Video #5: x64 Disassembling and Fixing obfuscated APIs with IDA

    In this one I compare two programs compiled in x86 PE format and x64 PE32+ format with GoAsm from the same source.

    Also previous download packages have been updated (some files were missing) and I added a warning about a bug when tracing with IDA 5.1 in video #3.

    Comments/Questions/Suggestions are always welcome.
    Categories
    Uncategorized
  10. Editable Listview control

    Few days ago I started renewing my PE editor's gui, I wanted to replace some edit box controls with a listview control. Everything was going well until I had to edit the value inside a cell. With the original listview control you can change the text of the first subitem of a row only, but I would like to edit every single subitem. How can I solve the problem? I didn't want to waste time solving the problem so I decided to take a look at the usual programming places starting from Code Project. Hm, nothing. I'm not so good in searching information through the net, but seems like there are working samples on mfc, .net and vb only. No win32 programming stuff... Well, I decided to give it a try subclassing the control.
    I have never subclass-ed a control before, it's my first try. I don't know if there's a better approach. I don't even know if it's the correct way to solve the problem, but it seems to works well. Let's start.

    The steps to follow are:
    1. Create an edit box that will be used to insert the new text
    2. Set the new window procedure able to handle edit control's messages
    3. Apply/abort text modification

    I use VS creating a win32 project. Add a listview control to your dialog setting "Edit labels" to FALSE. If you set the option to TRUE the OS will handle subitem modification, I prefer to avoid this behaviour.

    The idea is to change the subitem's text when a double click occours. I catch the event in the main window procedure calling the function (named SubClass_ListView_Editable) which subclasses the control.

    The first step consists of creating the edit box over the clicked subitem. To create the edit box I need to know where to put it. LVM_GETSUBITEMRECT returns information about the rectangle for a subitem of a listview control. With this information I can create the new control:
    Code:
    ListView_GetSubItemRect(hListView, _lParam->iItem, _lParam->iSubItem, LVIR_LABEL, &r);
    //    Time to create the new edit box
    hEditable = CreateWindowEx(0, "EDIT", "Edit me", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_MULTILINE, r.left, r.top, r.right-r.left, r.bottom-r.top, _lParam->hdr.hwndFrom, NULL, hInst, 0);
    "r" is defined as a RECT structure:

    Code:
    typedef struct _RECT {
    LONG left;        //      x-coordinate of the upper-left corner of the rectangle
    LONG top;        //    y-coordinate of the upper-left corner of the rectangle
    LONG right;      //    x-coordinate of the lower-right corner of the rectangle
    LONG bottom;   //    y-coordinate of the lower-right corner of the rectangle
    } RECT, *PRECT;
    As you can see I use "r" inside CreateWindowEx function specifying the coordinates of the new control.
    The third parameter of CreateWindowEx is the text that will be shown in the control. I use a static text but you can leave it blank or display the subitem's text, it's up to you. Now, the new control has been created and I'm going to set some features:

    Code:
    SendMessage(hEditable, EM_LIMITTEXT, 8, 0);        //    It accepts no more than 8 chars
    SendMessage(hEditable, EM_SETSEL, 0, 8);        //    Text selected
    SetFocus(hEditable);                    //    Focus to the new box
    If you don't need a particular behaviour (limit text, accept only numbers...) you can avoid the first two calls but I think the third one is useful, it gives the focus to the new edit box.

    The control is complete, I have to add the new window procedure. This can be done using SetWindoLong function:

    Code:
    LONG SetWindowLong(
    HWND hWnd,    //    Handle of the new edit control
    int nIndex,        //    The attribute to change
    LONG dwNewLong    //    The new value
    );
    The function changes an attribute of a specified window, in this case I'm going to change the address of the dialog procedure. The aim is to add a new window procedure for handling edit box's messages only. I'll pass over all the other messages forwarding them towards the old window procedure.

    Code:
    wpOld = (WNDPROC)SetWindowLong(hEditable, GWL_WNDPROC, SubClass_ListView_WndProc);
    SetProp(hEditable, "WP_OLD", (HANDLE)wpOld);
    SubClass_ListView_WndProc represents the new dialog procedure.
    I have to save the address of the original window procedure because I have to restore it when I'll destroy the edit box. To save the address I use SetProp function, but if you prefer you can use global variables. To end this piece of code I save some more useful information: row and column of the subitem to change:

    Code:
    SetProp(hEditable, "ITEM", (HANDLE)_lParam->iItem);
    SetProp(hEditable, "SUBITEM", (HANDLE)_lParam->iSubItem);
    Which kind of messages will I have to catch? WM_KEYDOWN and WM_DESTROY only, all the other messages are passed to the original window procedure in this way:

    Code:
    return CallWindowProc((WNDPROC)GetProp(hEditable, "WP_OLD"), hwnd, uMsg, wParam, lParam);
    I catch WM_KEYDOWN because I have to handle ENTER ans ESC key. When you hit ENTER the text will be saved in the subitem, and when you click ESC the operation will be aborted:

    Code:
    case WM_KEYDOWN:
    if (LOWORD(wParam) == VK_RETURN)
    {
    ...
    // Item and suibtem to change
    LvItem.iItem = GetProp(hEditable, "ITEM");
    LvItem.iSubItem = GetProp(hEditable, "SUBITEM");
    // Where to store the new text
    LvItem.pszText = text;
    // Get new text and set it in the subitem
    GetWindowText(hEditable, text, sizeof(text));
    SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)GetProp(hEditable, "ITEM"), (LPARAM)&LvItem);
    DestroyWindow(hEditable);
    }
    else if (LOWORD(wParam) == VK_ESCAPE)
    DestroyWindow(hEditable);
    break;
    If you press ESC the edit box will be destroyed without changing the subitem's text.
    When ENTER is pressed I simply get the text storing it in the subitem. After that I can destroy the edit box.
    There's something more to say about VK_RETURN. Look at CreateWindowEx parameters, there's a ES_MULTILINE value. The value is necessary otherwise the application refuses to catch ENTER.
    The last thing I check in the new window procedure is WM_DESTROY message, I simply remove the saved properties and then I restore the original window procedure calling SetWindowLong again.

    What about mouse click when I'm changing the subitem's value? It's like VK_ESCAPE key, I remove the edit box aborting the operation. See the attached source code for details.

    The picture represents the subclassing method in action:


    The code can be optimized for sure, just fix/change/remove/add everything you need.
    Feel free to post your comment/suggestion/criticism here.
    Download the VS project from http://www.box.net/shared/static/kcurtvm8v7.zip

    Game over!

    Updated November 6th, 2007 at 07:05 by ZaiRoN

    Categories
    Uncategorized
  11. IDA plugin: Extract (UnRot13) and analyze

    Some times ago I stumbled on a post at Offensive Computing where an user had some problems trying to figure out the encryption used by a malware (md5=36401cb9178232dde01b2788e8fc56f4).
    The malware contains 2 files located in the resource section. The files are encrypted, how to find out the encryption scheme? Well, using a debugger I would say. I didn’t start any debugger btw, deciding to take a look at the files using a resource editor. It’s a common thing to store files inside resource section. Here are the starting bytes of the first file:



    If you know which are the first common bytes in an exe file you should be able to figure out yourself which kind of encryption has been used. The presence of many 0×13 bytes is a nice hint, the file has been rot13-ed.

    In an old blog entry (http://zairon.wordpress.com/2007/07/11/ida-plugin-extract-and-analyze/) I talked about a little ida plugin able to extract and analyze an hidden file; I slightly changed the plugin adding the possibility to un-rot13 the hidden file. Take a look at the simple dialog:



    You can download the plugin from: http://www.box.net/shared/static/1kzvon1x67.zip
    Categories
    Uncategorized
  12. The Point-R technique

    Hello.

    While trying to track down a really difficult problem in the production version of our software that only manifested itself in certain configurations on SunW,
    i thought to myself... There Must Be A Better Way!

    So here, i present you the Point-R technique.
    It is very similar to the hmemcpy technique which we all miss so much, in that it will give you a jump start with any debugging problem.

    Just load the problematic file, be it a program of yours or something you need to crack, into ida and run point-r.upb.idc.

    Set a breakpoint on Point-R, let it run until the breakpoint breaks and you will be at the core of the problem at hand.

    The script will find Point-R by utilizing a series of successive complex approximations, much in the same way you would find a square root with some fixed precision.

    Enjoy and comment/enhance it!
    (and do not hesitate to correct my spelling/style errors [LLXX])

    Updated October 25th, 2007 at 21:01 by upb

    Categories
    Uncategorized
    Attached Thumbnails Attached Files
  13. Doing it without Weird Hacks (tm) is even easier

    why is this box so small?:P
    Code:
    /*
     * Import table maker (C) 2007 upb [at] preteam [dot] org
    */
    
    #include <string>
    #include <cassert>
    #include <vector>
    #include <map>
    #include <sstream>
    #include <iostream>
    #include <iomanip>
    
    typedef unsigned long DWORD;
    typedef unsigned short WORD;
    
    struct CornField
    {
    	typedef DWORD Groove;
    	typedef std::vector<unsigned char> t_ground;
    
    	void pick(std::stringstream& basket)
    	{		
    		for (t_ground::const_iterator iG = ground.begin(); iG != ground.end(); ++iG)
    			basket << *iG;
    	}
    
    	class OneHundredPercentPureAsm
    	{
    		OneHundredPercentPureAsm(CornField& isNot, Groove& theSolution) : isNot(isNot), theSolution(theSolution) { }
    		CornField& isNot;
    		Groove& theSolution;
    		
    		public:
    		void operator<<(WORD plant)
    		{ 
    			std::cout << "[" << std::hex << std::setw(4) << theSolution << "] W " << plant << std::endl;
    			isNot.poke(theSolution, static_cast<t_ground::value_type>(plant & 0xFF));
    			isNot.poke(theSolution, static_cast<t_ground::value_type>((plant >> 8) & 0xFF));
    		};
    
    		void operator<<(DWORD plant)
    		{ 
    			std::cout << "[" << std::hex << std::setw(4) << theSolution << "] D " << plant << std::endl;
    			isNot.poke(theSolution, static_cast<t_ground::value_type>(plant & 0xFF));
    			isNot.poke(theSolution, static_cast<t_ground::value_type>((plant >> 8) & 0xFF));
    			isNot.poke(theSolution, static_cast<t_ground::value_type>((plant >> 16) & 0xFF));
    			isNot.poke(theSolution, static_cast<t_ground::value_type>((plant >> 24) & 0xFF));
    		};
    
    		void operator<<(const std::string& plant)
    		{
    			std::cout << "[" << std::hex << std::setw(4) << theSolution << "] S " << plant << std::endl;
    			for (std::string::const_iterator kw = plant.begin(); kw != plant.end(); kw++)
    				isNot.poke(theSolution, static_cast<t_ground::value_type>(*kw));
    
    			isNot.poke(theSolution, static_cast<t_ground::value_type>(0));
    		};
    
    		friend struct CornField;	// we become
    	};
    
    	OneHundredPercentPureAsm operator[](Groove& idx)
    	{
    		return OneHundredPercentPureAsm(*this, idx);
    	}
    
    	virtual void poke(Groove& target, t_ground::value_type seed)
    	{
    		if (ground.size() < target + 1)
    			ground.resize(target + 1);
    		ground[target++] = seed;
    	}
    
    	virtual Groove start() { return 0; }
    
    	t_ground ground;
    	friend class OneHundredPercentPureAsm;		// one
    };
    
    struct MirageCornField : public CornField
    {
    	MirageCornField(CornField::Groove horizonDistance) : CornField(), horizonDistance(horizonDistance) { }
    
    	virtual Groove start() { return horizonDistance; }
    	virtual void poke(Groove& target, t_ground::value_type seed)
    	{
    		Groove actual(target - horizonDistance);
    		Groove old(actual);
    		CornField::poke(actual, seed);
    
    		target += actual - old;
    	}
    
    	private:
    		CornField::Groove horizonDistance;
    };
    
    struct LibraryImport
    {
    	LibraryImport() : ordinal(0) { };
    	LibraryImport(DWORD target, const std::string& name) : ordinal(0), target(target), name(name), hasName(true) { }
    	LibraryImport(DWORD target, WORD ordinal) : target(target), ordinal(ordinal), hasName(false) { }
    
    	void plant(CornField& cornField, CornField::Groove& hole, CornField::Groove& nest) const
    	{
    		if (!hasName)
    		{
    			cornField[hole] << static_cast<DWORD>(0x80000000 | ordinal);
    		} else
    		{
    			cornField[hole] << nest;
    			cornField[nest] << ordinal;
    			cornField[nest] << name;
    		}
    	}
    
    	DWORD target;
    	std::string name;
    	WORD ordinal;
    	bool hasName;
    };
    
    typedef std::pair<std::string, LibraryImport> LibraryImportPair;
    
    struct ImportLibrary
    {
    	ImportLibrary& operator<<(const LibraryImportPair& rhs)
    	{
    		name = rhs.first;
    		return *this << rhs.second;	
    	}
    
    	ImportLibrary& operator<<(const LibraryImport& rhs)
    	{
    		if (imports.find(rhs.target) != imports.end())
    			throw new exception("target occupied");
    
    		imports[rhs.target] = rhs;
    		return *this;
    	}
    
    	virtual void plant(CornField& cornField, CornField::Groove& libGroove, CornField::Groove& nameGroove) const
    	{
    		CornField::Groove hop(nameGroove);
    		cornField[libGroove] << hop;											// OriginalFirstThunk
    		
    		nameGroove += sizeof(DWORD) * (imports.size() + 1);
    
    		for (t_imports::const_iterator iImp = imports.begin(); iImp != imports.end(); ++iImp)
    			iImp->second.plant(cornField, hop, nameGroove);		
    
    		cornField[hop] << static_cast<DWORD>(0);
    
    		cornField[libGroove] << static_cast<DWORD>(-1);			// TimeStamp
    		cornField[libGroove] << static_cast<DWORD>(-1);			// ForwarderChain
    		cornField[libGroove] << nameGroove;								// Name
    		cornField[libGroove] << unbelievablyTrickyCalculation();	// FirstThunk
    
    		cornField[nameGroove] << name;
    	}
    	
    	DWORD unbelievablyTrickyCalculation() const
    	{
    		return imports.begin()->second.target;							// Assume webbits havent eaten any corn between
    	}
    
    	typedef std::map<DWORD, LibraryImport> t_imports;
    	t_imports imports;
    	std::string name;
    
    	static const CornField::Groove	GrooveAllocation = sizeof(DWORD) * 5;
    	static ImportLibrary* FieldEnd;
    };
    
    struct LastImportLibrary : public ImportLibrary
    {
    	virtual void plant(CornField& cornField, CornField::Groove& libGroove, CornField::Groove& nameGroove) const
    	{
    		cornField[libGroove] << static_cast<DWORD>(0);
    		cornField[libGroove] << static_cast<DWORD>(0);
    		cornField[libGroove] << static_cast<DWORD>(0);
    		cornField[libGroove] << static_cast<DWORD>(0);
    		cornField[libGroove] << static_cast<DWORD>(0);
    	}
    };
    
    ImportLibrary* ImportLibrary::FieldEnd = new LastImportLibrary();
    
    struct ImportDirectory
    {
    	typedef std::map<std::string, ImportLibrary> t_importLibraries;
    
    	ImportDirectory& operator<<(const LibraryImportPair& rhs)
    	{
    		libraries[rhs.first] << rhs;
    		return *this;
    	}
    
    	void plant(CornField& cornField) const
    	{
    		CornField::Groove libGroove = cornField.start();
    		CornField::Groove libNameGroove = libGroove + (libraries.size() + 1 ) * ImportLibrary::GrooveAllocation;		
    
    		for (t_importLibraries::const_iterator iLib = libraries.begin(); iLib != libraries.end(); ++iLib)
    			iLib->second.plant(cornField, libGroove, libNameGroove);
    		ImportLibrary::FieldEnd->plant(cornField, libGroove, libNameGroove);
    	}
    
    	t_importLibraries libraries;
    };
    
     // <3 operator abuse
    LibraryImportPair operator/(const std::string& lhs, const LibraryImport& rhs)
    {
    	return std::make_pair(lhs, rhs);
    }
    
    int main(int argc, char* argv[])
    {
    	MirageCornField field(0x0010000);
    	ImportDirectory imports;
    	imports << "kernel32.dll" / LibraryImport(0x11223300, "ExitProcess")
    		<< "user32.dll" / LibraryImport(0x11224400, "DialogBoxParamA")
    		<< "kernel32.dll" / LibraryImport(0x11223304, "ZzZzzZ")
    		<< "kernel32.dll" / LibraryImport(0x11223308, "AaaAAAaExW");
    
    	imports.plant(field);
    	std::stringstream basket;
    	field.pick(basket);
    
    	for (size_t i = 0; i < basket.str().length(); ++i)
    	{
    		std::cout << std::hex << std::setw(2) << std::setfill('0') << (unsigned long)(basket.str()[i] & 0xFF) << ' ';
    		if ((i + 1) % 16 == 0)
    			std::cout << std::endl;
    	}
    	return 0;
    }
    
    /*
     * Warning to certain individuals: do not try to copy paste this code into tutorials, i will understand by the variable naming :p
    */
    .
    Categories
    Uncategorized
  14. imports are easy to fix

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

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

    Code:
    00BBC368 >7C80A447  kernel32.QueryPerformanceCounter
    00BBC36C >7E450702  USER32.MessageBoxA
    
    kernel32.QueryPerformanceCounter = BBC364
    user32.MessageBoxA               = BBC368
    You might wonder how did I get this to work? Using API loader? No!!!

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

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


    So what we shall do to make this concept work?

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

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

    First we define some struct which will hold our imports:

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

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

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


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

    Code:
                            sub     edx, size import_struct
                            
    __cycle_main_loop:      add     edx, size import_struct
                            cmp     [edx.is_address], 0
                            je      __done_building
                    
                            ;copy dll name
                            mov     esi, edi
                            sub     esi, new_iat_mem
                            add     esi, iat_sec_rva
                            
                            mov     [ebx.id_name], esi 
                            lea     esi, [edx.is_dllname]
                            mov     ecx, [edx.is_dlllen]
                            rep     movsb
                            
                            ;write original first thunk
                            mov     esi, eax
                            sub     esi, new_iat_mem
                            add     esi, iat_sec_rva
                            
                            mov     [ebx.id_originalfirstthunk], esi
                            
                            mov     esi, dword ptr[edx.is_apiname]
                            test    esi, 80000000h
                            jz      __api_has_name
                            mov     [eax], esi
                            jmp     __firstthunk         
    
    __api_has_name:
                            mov     esi, edi
                            sub     esi, new_iat_mem
                            add     esi, iat_sec_rva
                            mov     [eax], esi
                 
                            lea     esi, [edx.is_apiname]
                            add     edi, 2
                            mov     ecx, [edx.is_apilen]
                            rep     movsb
    
    __firstthunk:                        
                            mov     esi, [edx.is_address]
                            mov     [ebx.id_firstthunk], esi
                            
                            add     ebx, size import_directory
                            add     eax, 8
                            jmp     __cycle_main_loop
    When this small loop is done, all we have to do is to walk all first_thunks and set them
    to != 0 so win loader can actually load this import table.

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

    MessageBoxA
    GetModuleHandleA
    RegOpenKeyExA

    etc...

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

    Think about it when writing unpacker and protection developers think too when
    you try to make "hard" IAT to stop importrec, you will lose one way or another
    Remember that not many people are using it lately

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

    Categories
    Uncategorized
  15. New Video Tutorials website

    New addition to the Reverse Code Engineering Community Forum:
    http://community.reverse-engineering.net
    (in the useful places box below)

    We now have a new website for video tutorials.
    http://video.reverse-engineering.net

    3 video tutorials about IDA are already online.
    #4 has just been finished, it should be added soon.

    They are mostly aimed at beginner to intermediate reversers, made in the Lena151 style.

    1. Introduction to Visual Debugging with IDA's Graphical View
    2. Remote Debugging a Linux (DVL) program from Windows / IDA for Linux
    3. Debugging a buggy program through Watching variables and Instruction tracing.
    4. How to solve crackmes for newbies / "Making of" of the keygen

    New videos will be added as time goes by.

    The site will be improved soon, the first goal was to have it online.
    Categories
    Uncategorized
Page 10 of 11 FirstFirst ... 34567891011 LastLast