SOFTWrapper: wrapping galore
An encryptionless wrapper is a protectionless protection
Programmers
Programmers
2-10-98
by HalVar+
Courtesy of Fravia's page of reverse engineering
 
fra_00E5
980213
Halvar+
1100
PC
XX
Very interesting essay... as HalVar+ writes: "A funny thing about reversing: While you're at it, it all looks new and interesting,and after you're done, you're often surprised how trivial the actual crack you considered interesting 5 minutes ago is..." it is true, in a sense, yet real knowledge is like that: ad astra per aspera. Enjoy this essay: you may learn something about code relocation as well reading it...
Feudalism: It's your count that votes
Rating
(x)Beginner (x)Intermediate ( )Advanced ( )Expert

A little essay on how to execute only the parts of a wrapper we like; only those which are necessary to run the main program. Plus some ideas on how a "generic" crack for all programs protected with this wrapper could be created. Interesting for newbies, experienced +crackers will hardly find anything new.
SOFTWrapper -- an easy to bypass wrapper
An encryptionless wrapper is like a protectionless protection
Written by HalVar+


Introduction
A trend you could see for a while (and which still hasn't completely
disappeared) are the so-called "plugin-protections", like RSAGNT32.DLL
and the like. Some of the IMO most stupid ideas ever were the so-called 
"Wrappers" which basically wrap a finished executable with a "protection
envelope". I will crack a very antiquated example of these wrappers to 
demonstrate how to bypass the parts of the wrapper we do not like while 
executing the parts we need to execute. 


Tools required
SoftICE 3.01
TASM (optional)

Target's URL/FTP
Do an ftp-search on WRAPEVAL.ZIP (175.157 bytes) :-)

Program History
No history, no future, no wonder :-)

Essay

In recent times we've seen a drastical increase in so called "Plug&Play" protections which vary greatly in strenght. Some are fairly strong, but many of them (especially the earlier ones) are nothing but junk to take money from the already cracker-newbie-battered shareware authors.

The probably weakest version of these "P&P"-protections are those which do not even require the programmer to integrate them into their program source, but which take an executable and "wrap" it instead.

The target we're examining here is itself an evaluation version, but so sadly crippled and even in it's full version useless. It is not good for anything, and the readme.txt points out that it was released in 96 and never used. No wonder if you look at what it does, but for a first study it can help pull some things together.

This wrapper will add a time/date check to an existing file. While I am sure it would be trivial to crack the time check or the registration routine, I am sick and tired of the same stupid Registry-Keys or RegKey-checks. I want to completely bypass everything I do not need and as quickly as possible transfer the control back to the wrapped program.

Since this wrapper is attaching it's functions to an existing file which are then to be executed before the main program is, it acts in certain ways like a virus. So what do those AV-people do again to figure out how a virus works ? They create tiny bait files to be infected and examine them afterwards.
For this purpose I dug my first Win32-ASM-File out. Well, I think everybody has one or two like these lying around, but I'll give you the short source nonetheless :
----------------------------------cut here------------------------------------
; HalVars 1st Win32 Program, a bait file to be wrapped

.386P
Locals
Jumps

.Model Flat, StdCall

Extrn   ExitProcess:PROC
Extrn   MessageBoxA:PROC


.data

title_box1    db   'HalVar`s Bait', 0
Box_textSTART db   ' Now you can choose : :-)',0
Box_textYES   db   'You pushed the YES Button !',0
Box_textNO    db   'You pushed the NO Button !',0
Box_textEXIT  db   'Do you want to repeat the whole crap ??',0

.Code
  Main:
     beginhere:
        xor bx, bx
        mov bx, 0004h

        push bx
        push offset title_box1
        push offset Box_textSTART
        push 0
        call MessageBoxA

        cmp  ax, 6
        je   Yes_Box

        mov   bx, 10h
        push bx
        push OFFSET title_box1
        push OFFSET Box_textNO
        push 0
        call MessageBoxA
        jmp  EndIt

      Yes_Box:
        mov  bx,10h
        push bx
        push OFFSET title_box1
        push OFFSET Box_textYES
        push 0
        call MessageBoxA

      EndIt:
        mov  bx, 0004h
        push bx
        push OFFSET title_box1
        push OFFSET Box_textEXIT
        push 0
        call MessageBoxA

        cmp  ax, 6
        je   beginhere

        push LARGE-1
        call ExitProcess
End Main
---------------------------------cut here-------------------------------------
Quit laughing already ;-)

The advantage of using a tiny bait file like this is that you know your code 100%ly, and that you'll definitely recognize anything that is not part of the original program. Lateron, you should test your findings on a bigger target, but right now, this one is enough.

Allright, the code is self-explanatory. Compile it, then make a copy of it before you wrap it. Load the unwrapped bait into the SICE-Loader, go through the whole thing once to know what's going on.
Enter some small explanatory strings for the MessageBoxes created by the wrapper and run the wrapped bait file, and you'll be prompted with a MessageBox which asks you something like "Not expired yet. You want to register now?", and YES/NO-buttons.

Now, since we don't want to crack the registration mechanism, click on NO, and there you are:
Our bait file. Quit it and load it again, this time in the SICE loader.
The loader will go into SICE at the first instruction of your program.
Funnily enough, the program does not start at 00401000 any more, but at 00407000 with the following instructions:

:00407000  call 00407005       ; Hey, it's the old trick to find the  
:00407005  pop ebp             ; delta-offset again :-)  
:00407006  mov eax, ebp        
:00407008  sub eax, 00006005   ; eax now contains 00401000, the original
:0040700D  push eax            ; program starting point, while bp contains
:0040700E  sub ebp, 00000005   ; 00407000, the starting point of the wrapper
Well, old tricks never die: The mysterious (?) call is necessary to know the address of the wrappers' variables, the so-called "delta-offset". This is a big name for something so easy: If you write a program which is intended to append itself to another program, it can't reference to it's own variables in the standard way:
lea ax, OFFSET title_box1
will not work, since the offset will be compiled to an absolute address. Naturally, these addresses change when the program is appended, so the above snippet would have to look like this in order to work in an appended program (assuming bp contains the delta offset):
lea ax, [bp+OFFSET title_box1]
For more questions concerning the delta offset, consult your local virus site.

I could hardly believe it: There, at 00401000, the original program entry point, lay my own program unencoded, not even XORed :-) This truly IS a weak wrapper.

When I looked at this, I, full of youthfull enthusiasm and naivity, thought "This is too easy !" and made the following change:
:0040700D jmp eax  ; JMP to the beginning of the unwrapped program
And rubbing my hands in glee, I was surprised to see my computer splatter in slo-mo and full color, giving me first a few GPFs and then a stack fault.
So I rebooted, got myself a cup of good tea and looked again. I did the same change, this time not exiting, but tracing into my own program.
And what did I have to see ?
:00401009  push 00402000 ; Points to the "HalVar's Bait"-String
:0040100E  push 0040200E ; Points to the "Now you can choose"-String
:00401013  push 00000000 
:00401015  call 0040107A ; But hey, isn't this supposed to be [MessageBoxA] 
                         ; instead ?
The fact that the call references to an address instead of the function it is supposed to call to tells us that the imports haven't yet been loaded for this particular program. So I we'll have to step to our program a bit longer before we can jump back to our own code.
So we fire our program up another time and step through the code until we reach a thoroughly interesting code snippet at
:00407076  add dword ptr [esi+02], eax  ; eax contains 00400000
:00407079  add esi, 00000006            ; si points to a jumptable
:0040707C  loop 00407076                ; which starts at 00407A0D
The above snippet adds eax to the jumptable's locations, thus "importing" the most basic funtions which will lateron allow the wrapper to import further API-calls or dlls.
After it is finished, the jumptable looks like this:
:00407A0D  jmp dword ptr [Kernel32!GetSystemTime]
:00407A13  jmp dword ptr [Kernel32!LoadLibraryA]
:00407A19  jmp dword ptr [Kernel32!GetProcAddress]
:00407A1F  jmp dword ptr [Kernel32!FreeLibrary]
:00407A25  jmp dword ptr [Kernel32!ExitProcess]
:00407A2B  jmp dword ptr [Kernel32!GetModuleFileNameA]
:00407A31  jmp dword ptr [Kernel32!GetModuleFileHandleA]
:00407A37  jmp dword ptr [Kernel32!GetVolumeInformation]
:00407A3D  jmp dword ptr [Kernel32!CreateFileA]
:00407A43  jmp dword ptr [Kernel32!WriteFile]
:00407A49  jmp dword ptr [Kernel32!CloseHandle]
:00407A4F  jmp dword ptr [Kernel32!WinExec]
Well, this does look like a smorgasboard to everyone who wants to import more functions, but it does little more. None of these table entries include [MessageBoxA], which means that the imports the bait files need are located elsewhere.
When we trace into the next instruction, we encounter a call to a function located at 00407083; and there it is, finally : The importation of all functions needed by our BaitFile, as well as the usual crap the protection imports to check for expirations etc...

Now, for stability's sake, these functions should better be unloaded before our original program is run, therefore we bpx on 00407A1F. We end up (after 'p ret'ing our way back to our code) in the function which unloads all unneeded functions, located at 004079CE.

Finally, we got everything together to crack this crud. We change the code to the following:
:0040707e  call  00407889 ; Import all functions
:00407083  call  004079CE ; Unload all unneeded functions
:00407083  pop   eax
:00407083  jmp   eax
Voila, the crack is done.
A generic crack could be prepared easily for this, just search for the bytesequence "E8000000005D8BC5" (which is the beginning of the wrapped part). From there on you can calculate the offset for the bytes to patch. You would have to change the call, though to something that respects the delta offset, the address to call would be (bp+09ce).

This whole protection is incredibly easy to bypass, since it doesn't encrypt the wrapped program in any way. But one of the nice things about programmers: They tend to put things like en/decryption into nice functions, much like the function we called at 004079CE.

If there had been an decryption, you could've usually called it in a similar way we unloaded all unneeded functions.

This is in fact a pretty powerful way to bypass big parts of a protection: Figure out what the functions are doing and call only the parts you're actually using.
This does not hold true for any strong wrappers which decrypt only if the right serial is entered, but as long as the wrapper leaves you time to evaluate it, cracking should be a rather trivial task.
HalVar, February 1998


Final Notes
Well, apparently the programmers of this small prog read a few basic virus 
tutorials and had a few ideas, but while they were at reading these tutes
they could've dug out a few clever ways how to conceal what they're doing
and how to avoid being debugged like this. 

The one thing I learned (and give as advice to every beginner): Get yourself a few virus tutorials and learn how to program some DOS-Assembly, then learn how to program some simple Win32-Stuff in Assembler. This helped me a lot, and without it I wouldn't have written this textfile :-)
I'd like to thank/greet the following people:

Kneefalls go to: Mammon, Quine, Stone, NatzGul, Fravia, ORC, Razzia, DataPimp, Yoshi, the whole UCF as well as PhrozenCrew and Revolt...and everyone I forgot
Greets go to: Tin, blorght, bulll, all others in #C4N, Alia, Gnoof, iSa :-)


Ob Duh
I wont even bother explaining you that Fravia's ob duh paragraph doesn't apply to this program, since we're just reversing our own program ....

You are deep inside Fravia's page of reverse engineering, choose your way out:

progcor
Back to progcor

redhomepage redlinks redsearch_forms red+ORC redstudents' essays redacademy database
redreality cracking redhow to search redjavascript wars
redtools redanonymity academy redcocktails redantismut CGI-scripts redmail_Fravia
redIs reverse engineering legal?