²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² ²² ____ __ __ ²²ßÛ ²² / _/_ _ __ _ ___ ____/ /____ _/ / ²² ÛßÛ ²² _/ // ' \/ ' \/ _ \/ __/ __/ _ `/ / ²² Û Û ²² /___/_/_/_/_/_/_/\___/_/ \__/\_,_/_/ ²² Û Û ²² ____ __ __ ²² Û Û ²² / __ \___ ___ _______ ___ ___/ /__ ____ / /____²² Û Û ²² / /_/ / -_|_-</ __/ -_) _ \/ _ / _ `/ _ \/ __(_-<²² Û Û ²²/_____/\__/___/\__/\__/_//_/\_,_/\_,_/_//_/\__/___/²² Û Û ²² ²² Û Û ²² Web: http://www.ImmortalDescendants.org ²² Û Û ²² Author: Lord Soth ²² Û Û ²² Date: 06/08/2000 (mm/dd/yy) ²² Û Û ²² Topic: VB reversing, SmartCheck ²² Û Û ²² Level: Beginner/Intermediate ²² Û Û ²² ²² Û Û ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² Û Û ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ Û ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ ============================================================================ INTRODUCTION ============================================================================ Hello, folks. Yet another target is being used by us crackers to demonstrate how easily some reversing feats are accomplished :) OK, in this short essay I'll try to explain some basic stuff on how to reverse parts of VB programs. It seems many newbies are often very confused when it comes to VB. The main reason is probably because VB code is a lot more bloated than normal C/C++ code. Delphi also has the "feature" of bloatness as well. This bloatness is not only meant to save the programmer many things, it is also meant to make our lives harder, by making layer after layer of programs' and engines' code. An example for this is VB. Visual Basic is not only a comfortable development environment that beginning programmers find easy to learn and use, it is also a sort of an engine. This engine for programs goes a long way to save work for the programmer, leaving the "boring" stuff to the engine. This is done using a very big DLL with many functions and services, and also thousands of lines of code added to the program. This in effect makes our cracking lives harder. The more code there is, it is supposedly harder to reverse. In effect, sometimes this is true, but usually only for newbies. Experienced crackers are well.. experienced enough to know how to look for the important things in a program, and cut straight to the protection code. However, those without an abundance of experience are overwhelmed by the VB code. Not only its size, but also its form. Things are done very differently in VB. For this end, Numega wrote SmartCheck. OK, maybe this is somewhat incorrect. They didn't write SmartCheck for us crackers, they just wrote it to help speed the development and debugging of VB applications. This is done using, among other things, a sophisticated type of logging that SC does. This logging and reporting is what helps us understand what the program is doing. In effect, that's reversing, isn't it? What disassemblers such as W32dasm, and IDA pro are doing for us, is giving us some sort of a sense for the bigger picture. The details are unimportant, and can usually be fished out easily with a debugger such as our beloved SI. However, understanding of the great scheme of things is so important in this "line of work", and since VB is so bloated and different from normal code, then SmartCheck (SC) is our last best refuge. So, in this essay I'll show, very easily I might add, how incredibly easy it is to locate important pieces of code of an application. Without too much blabbering, lets get down to it then!! ============================================================================ TOOLS NEEDED ============================================================================ SmartCheck (of course, that's the whole point!) SoftIce (ver 3.2x will do) W32dasm (or IDA if you feel you need to, I think its a waste of time for this protection) HexWorkShop (my fav. hex editor, just love it!! :) ============================================================================ THE TARGET - CONVERT VERSION 1.5 ============================================================================ This is a small program, and I got it from a friend of mine, so I have no idea how to get it from the Internet. My bet is a search might find it, eheh :) ============================================================================ ANALYZING THE PROTECTION ============================================================================ Well, after installing the app, and running it, we get the pleasure of seeing a nag screen. The nag screen says some unimportant stuff, and has a timer that is counting down from 10 to 0 (in seconds of course). Another thing to see is that the OK button is grayed, so it can't be clicked. Yep, you guessed it, when the counter reaches 0, the OK button will probably be enabled again. This is nice. In usual programs, this shouldn't be too much trouble to take care of. Another thing to look at is that when exiting the application, the same nag appears. In fact, this is the About dialog box for this program, however, if you were to click the About button in the main window app, which is opened by double-clicking the tray icon btw, you'll see that the About box is fully functional, with no timer. This means that the program is using the About box as a nag screen in startup and exit, but with some changes. Several ways to crack this comes to mind. One can manipulate the timer, one can enable the OK button, and one can even remove the nag altogether (the best option). Now, let me clarify something. this is the first time I've used SC to actually crack a program. I haven't cracked MANY VB apps, but I cracked a few, without the use of SC. What I usually did is to find some imports from the DLL that are incriminating, that is, somehow related to the type of protection. Other methods are breaking on windows API functions that you know are used by the VB DLL, hoping somehow to return back to the calling program. Other methods are available of course. One such approach is to look for interesting string refs using W32dasm. I must emphasize that if you don't have the patch for W32Dasm that enables you to view the string refs, you might as well forget this method. Get the patch, it can shed some light into the app :) What we'll do here is to mainly use SmartCheck to locate where events happen inside the VB program. We'll need a disassembly as well just in order to verify that the code locations we enter are actually valid, otherwise we'll waste our time trying to break on them with SI. We won't need to use SI a lot, but we'll go in with it in order to see if the code locations we get from SC are actually related to the protection. Ok, now, disassemble the program using W32Dasm like the good boy/girl that you are and save the project file. Open it in SC and run the program. When the nag ends, exit the program, and exit it also on the tray, cause its one of those annoying programs that wanna stay minimized forever in your system :) After this is done, have a look at the report generated by SC. You can also save the report/log into a SCE file. This is handy, you won't need to run the app again. I suggest doing it, unless circumstances show that it would not be a good idea. Lets have a look then. The first part we see is called Initialize, and it has a plus sign next to it, as it can be expanded. Lets expand it and see what's going on. A few lines down into this part, we see something called "Form1_Load". This is interesting. Form1 is usually the main Form used by VB apps. This is somehow equivalent to the main window in a normal program. In design time, VB programmers create the forms, and controls inside them, or at least that's what I was told :) So, its safe to assume in that part we can find interesting stuff about the creation of the windows and controls inside the program. Lets have a look inside it, and peek into it. Click the plus sign next to it to reveal some nice looking wonders. These are all actions performed by the program, and were 'recorded' by SC. Now, scroll down, looking for anything interesting. I did this search only because I needed to. No special thought process lead me to search this place, it was just an attempt to locate some important stuff. Sure enough, after quite a few lines, you get to another interesting part, now called: "frmAbout (Form) Created". What does it mean? Well, it probably means that another child form has been created, and well, look at it's name, frmAbout. This is the hint we need. This seems like the place the program is creating the About dialog. Look at the right pane, and you'll see where in the program this event happened, along with any parameters it might effect. In effect, creating forms does not require changes to parameters, unlike conversion from a number to a string or something similar. When looking at the code location, I saw this : MSVBVM50.DLL!00028FAD. Below was the ID of the form. Well now, this doesn't look like a good thing, or rather it doesn't look like a useful thing in our eyes. The creation is done inside the VB DLL, therefore it's not interesting. We need code specific to the program. A line below we see this : "frmAbout_Load". This tells us that the designed form is loaded into memory, prepared to go. What does LOAD mean? Well, if you're interested, click the plus sign to see what goes on in there. What you'll see is some strings and stuff handled around. I think you can understand that this part initializes most of the controls (yes, even static text controls) inside the About box. Notice however that there is no reference here to the OK button or the timer used. This probably is NOT what we need to deal with then. Collapse the frmAbout_Load part click the minus sign, and lets move on. Looking at the next few lines, we see some interesting stuff indeed. An integer with a value of 10 is converted into a string (VB strings are wide char btw), and then that string is used to initialize a label (in normal programming concepts, this is referred to as a static text control). Right after this, we see another interesting thing: cmdOK.Enabled <-- False (Boolean) What does that mean? Well, most likely this is the disabling of the OK button in the About box. The type of parameter is a boolean false, which is passed to what is probably a method (class function) called Enabled. Not sure about this as I never programmed in VB, but it seems that way. Now, we have the integer 10, which is probably related to the 10 seconds counter and we have the OK command disabled, this alone is interesting enough to warrant diving into SI and looking for some stuff to trash. Before we do this though, I suggest using W32Dasm to go to these code offsets. We find the integer is initialized at CONVERT.EXE!0003C845. Well, this can mean more than one code location. As you know, disassemblers often refer to code locations as offsets from the beginning of the EXE file in question, so it's safe to assume that this is the case. I found it to be the case only on rare occasions. In order to find such a code location in the disassembly, we'll need to go the location, and then move down or up untill we see in the bottom of the W32Dasm screen that we're exactly at the offset we got from SC, but in the EXE file. As I said, this usually is not the case. What IS usually the case, is that SC reports events as the DLL is being called into. It logs the address of the instruction that invoked the service, and it removes from it the ImageBase for the code section. Don't ask me why, but that's how it is. Probably so you have an offset from the beginning of the code, instead of having an absolute address. This is good because on rare occasions, code blocks are being transferred to other parts in memory. Ok, great, we saw that the offset for the integer loading with 10 is 0003C845. Let's add the ImageBase, which I found to be 400000h (not 401000 as most will guess, or the program reports). Even if the IBase was at 401000h, the code location in question is an offset from the application instance, which is 400000h (normally). I won't go into any detail about the hInstance, but it should be familiar to any windows programmer. Now, adding the two I got 0043C845h. Now let's load the program with the symbol loader, and SI pops, we're at the entry point. Now lets BP on that location, either using G, or using BPX: bpx 43c845 Now hit F5 to let it run, and we've stopped at this location : * Reference To: MSVBVM50.__vbaFreeObj, Ord:0000h | :0043C83E E8DB53FCFF Call 00401C1E :0043C843 6A0A push 0000000A * Reference To: MSVBVM50.__vbaStrI2, Ord:0000h | :0043C845 E89253FCFF Call 00401BDC ;<<< we're HERE!!! :0043C84A 8945E0 mov dword ptr [ebp-20], eax :0043C84D A110314400 mov eax, dword ptr [00443110] :0043C852 85C0 test eax, eax Now look at what's going on. The function __vbaStrI2 is being called here. This is also the exact location reported in SC that we found. Now, see what is being pushed ?? the parameter is in fact 0Ah, which is 10. Then the CALL is executed, and from its name I bet it takes an integer and converts it into a VB string (wide char of course). Confirm this by stepping over the funtion call, then EAX will contain a pointer to the new string. This is common in VB. The return value is often a pointer to the "result" of the operation being done. To verify this, display the memory contents at the address pointed to by EAX: d eax In the data window you'll see 1.0.. and some other stuff next to it. This is a wide char string. It stands for 10. Now we know where the integer gets converted into a string. Now, in an app that respects its protection, this would only be the text displayed, not the REAL counter that is probably initialized earlier and in a different location. But, wonders never cease, and we should check the option of this being the REAL counter. Rerun the program and break in the same place, now, you see that the push was already executed, so display the contents in ESP: d esp, then edit the 0a into 00. Or you could just change the BPX to 43C843, to catch it before pushing the 10 to the stack. Once you change it, continue execution (F5), and woa!!! the counter is initialized with 0 !!! WOW we think, this guy actually used the label's integer as a counter. How it's done is usually not important, but if you're interested, a few lines down you can find this: frmAbout.Show. This just looks to me as calling of the Show method, which will probably make the form visible. Now, inside the Show event, we find many timer events. Open a few of them, poke around and you'll probably get to the same conclusion I have, which is the guy that coded this app used the label's text (the counter text, the number itself) in order to update it's value. This means that if the counter shows 10, it'll convert the "10" string into a decimal 10, decrease one, and shove it back into the About box. That's a pretty lame way of doing it, but we're not gonna get mad at this guy, cause we're nice :) OK, close the Show event down, and lets move on. We managed to make the counter start at 0, which will cause the OK button to almost immediately be enabled, thus allowing us to continue past the nag. However, we also found out where the button is initially diabled, which is not too far away if I recall. It was at offset 0003C8D9, which is in SI's language, equal to 0043C8D9. So put a bpx there, and lets move on. I pasted the relevant lines of code in here: :0043C8D1 8BF0 mov esi, eax :0043C8D3 6A00 push 00000000 :0043C8D5 56 push esi :0043C8D6 8B06 mov eax, dword ptr [esi] :0043C8D8 FF908C000000 call dword ptr [eax+0000008C] :0043C8DE 85C0 test eax, eax :0043C8E0 7D11 jge 0043C8F3 :0043C8E2 688C000000 push 0000008C :0043C8E7 68BC984100 push 004198BC :0043C8EC 56 push esi :0043C8ED 50 push eax * Reference To: MSVBVM50.__vbaHresultCheckObj, Ord:0000h | :0043C8EE E8A353FCFF Call 00401C96 One thing to notice here is that the PUSH at address 43C8D3 is actually viewed in SI as: PUSH 00, which fits the opcode 6A00 that comes along with it. Now, how is this important? Well, if you've seen boolean params passed on the stack, you'll know that FALSE is 00, and TRUE is 01. So my bet is that the PUSH 00 is the FALSE parameter passed to the Enable method of the form object. Again you can change the passed param on the stack as I described earlier, or you could rerun the program, putting a new BPX at address 0043C8D3. Another thing to notice, and this is very important, is that SC reported this event occured at address 0043C8D9, which *SHOULD* be the function call that generated the event, however, as you can see, the actual address of the CALL instruction is at 0043C8D8, so SC missed it by a byte. This is why we need a disassembly. With it, we can make sure where exactly to put our BP in SI so that we actually break, and not just gaze at the screen when program execution continues without popping our debugger. OK, so now try to run the program again, but at 0043C8D3, assemble a new instruction, either by being on it and typing 'a', or whatever. As you guessed by now, this new instruction is going to be: push 01. Now continue execution and you'll see the OK button enabled from the start, and even if you neglected to change the counter to 0 again, this will let you continue ignoring the counter. So we found another nice way to crack this app, we don't even need to bother with the timer, we can just enable a button, which is a 1 byte patch!!! HOW COOL!!! But we are aiming for perfection, if we can, so we will typically want a nag to be completely REMOVED (or killed as I like to say!). After all, nag screens were MEANT to be killed!!! hehe Let's try to find out where exactly the program is popping this nag up. My first guess is that the Show method is what is used to make the About box come to life. I must admit, at first I did not think of this. I wanted it to NOT even create the About form, but then I was told by Golem that in order to invoke the form, a method has to be called, and its usually easy to disable these calls. So I went in again, stepping over calls from my last known code location, which was the preparation of the OK button. After a few dozen lines of code, I've stumbled upon this: * Reference To: MSVBVM50.__vbaNew2, Ord:0000h | :0043C958 E8FD52FCFF Call 00401C5A * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0043C954(C) | :0043C95D 8B1D10314400 mov ebx, dword ptr [00443110] :0043C963 83EC10 sub esp, 00000010 :0043C966 8D75B8 lea esi, dword ptr [ebp-48] :0043C969 8BFC mov edi, esp :0043C96B 8B03 mov eax, dword ptr [ebx] :0043C96D C745C004000280 mov [ebp-40], 80020004 :0043C974 C745B80A000000 mov [ebp-48], 0000000A :0043C97B 83EC10 sub esp, 00000010 :0043C97E A5 movsd :0043C97F A5 movsd :0043C980 A5 movsd :0043C981 A5 movsd :0043C982 8D75C8 lea esi, dword ptr [ebp-38] :0043C985 8BFC mov edi, esp :0043C987 C745D001000000 mov [ebp-30], 00000001 :0043C98E C745C802000000 mov [ebp-38], 00000002 :0043C995 A5 movsd :0043C996 A5 movsd :0043C997 A5 movsd :0043C998 53 push ebx :0043C999 A5 movsd :0043C99A FF90B0020000 call dword ptr [eax+000002B0] :0043C9A0 85C0 test eax, eax :0043C9A2 7D11 jge 0043C9B5 :0043C9A4 68B0020000 push 000002B0 There is a reason why this part I pasted is so big. When stepping, I noticed it continually checks the object in question, and if somehow it's invalid, it calls the __vbaNew2 function. This is probably a safe check mechanism either put there by VB, or by the application. My bet goes to the VB engine, that probably is doing endless checks to see if everything is valid all the time. Most of these checks are redundant. Now, if the object is created and is OK, we jump to address 0043C95D, which in turn puts the handle of the object (or what I assume to be the handle of the object), into EBX. The stack is then used to allocate some more space, and some stuff are being done, and eventually we get to 0043C99A. I stepped through this function call, and saw the About box come to life on my screen. I waited patiently for the counter to finish, to see if I'm returning to SI after it's destroyed, and indeed I returned into SI and was put right after that function call. It was obvious to me what I needed to do in order to kill this nag. I needed to jump over the call. This also means jumping over all the parameters and stack space allocated for this call. We'll need to jump over the SUB ESP,00000010h then, at address 43C963h, and all of the other code that lies afterwards. This can easily be done like this: a 43c95d Now I'm entering the following instructions: XOR EAX,EAX XOR EAX,EAX JMP 43C9A0 The XOR EAX, EAX will zero out eax, and I need it to be 0 to signal the app so the right condition in the JGE at 43C9A2 will be met. This will ensure that the result for the form object is not checked as you can see a few lines down a call to __vbaHresultCheckObj function. This probably checks the result of an operation done on an object. We want it to believe that the operation is the closing of the About box, after the timer has elapsed. Modifying these bytes in memory gives me the opcodes I need to use in my patch. Those are a totoal of 6 bytes in memory, and it was designed to be this way because the instruction which I'm overwriting at 0043C95D is 6 bytes long. Now, back in W32Dasm, go to the code location 43c95d, and you'll see at the bottom that the offset in the EXE file for this instruction is 3BD5Dh. Open the EXE in HexWorkShop and edit the bytes from whatever they were to 33,C0,33,C0,EB,3D (if I'm not mistaken). Close stuff and rerun the program, and you'll see it works without the nag both in startup and in shutdown. Now click the About button in the main application window and you'll see the NORMAL About box is still working properly :) OK, now there is another way to reach the even at 0043C99A that we found. In SC, you can easily see that the Show method is at 3C99Bh. Looks somewhat suspicious?? They are almost identical!! This means that SC missed the CALL by a byte, but that is exactly where we need to break with SI to enable the About box, and thus if I was paying more attention, I would have seen this without stepping through a few dozen lines of code. The patching is left for you I bet, from here it's trivial, like most math professors say :) ============================================================================ CLOSING WORDS - SUMMARY ============================================================================ Well, I hope this kinda short tutorial showed you how EASY it is to find just the right important stuff inside a VB app to quickly crack it. Now I'm not saying that ALL VB apps can be cracked so easily, but I am saying that SmartCheck goes a LOOOOONNNGGGG way of making our work easier. It just makes all the real work of the program visible to our eyes in a comfortable list (almost) for us to search in. I bet it's actually a pretty good VB debugging tool when coupled with VB and the program's source code :) Once again, the boys at Numega have proven they know what it takes to debug, reverse and analyze running stuff, even if we don't have the sources ready for our inspection. The only people that actually managed to come close to this IMO are the boys from DataRescue with their mighty IDA disassembler. In any case, I hope this tutorial helped you understand SOME of what is going on inside VB applications, and make the boogy man not so BOOGY, or evil :) This is it, cya all next time! For comments, contact me at : lordsoth8@hotmail.com LordSoth@ImmortalDescendants.org or via ICQ : # 5178515 Happy cracking! ============================================================================ GREETINGS ============================================================================ Greetings go to ALL the Immortal Descendants members, all the +HCU members, the +Sandman (I owe him special thanks , since because of him I am what I am today), The Snake (my dear friend), The Hobgoblin (just love that guy :), Lazarus (love him too, loved the Laz_Calc.. hehe), and Jeff of course, all those that visit the Newbies Forum, +Fravia, +Frog's print, +tsehp, DQ, _mammon, and all those gods of knowledge that roam the cyberspace and occasionally rear their heads either at +fravia's forum or the newbies forum... Of course, Ghirrizibo (not sure how to type it) for his wonderful IceDump util, and many other I probably forgot, if I did, I apologize!!