|
VB Decompiler Hosted by TheAutomaters.com
|
Author |
Message |
vbgamer45 Regular user
Joined: 07 Jul 2004 Posts: 93 Location: 127.0.0.1
|
Posted: Sun Jul 30, 2006 3:27 am
Post subject: Disassembling Visual Basic Applications
|
|
[font=Courier New:3n85y0p4]********************************************************************************
* DISASSEMBLING VISUAL BASIC APPLICATIONS - II *
* - Sanchit Karve *
* *
* born2c0de *
* printf("I'm a %XR",195936478); *
* *
* CONTACT ME : born2c0de AT dreamincode DOT net *
* *
********************************************************************************
LAST UPDATED : 13 NOVEMBER 2006
--------------------------------------------------------------------------------
INDEX [INDX]
I. DISCLAIMER AND NOTICE [DISN]
II. READING THIS TUTORIAL [RTUT]
III. ASSUMPTIONS [ASPT]
IV. REQUIRED TOOLS AND DOCS [RQRT]
V. VB AS A LANGUAGE [VBAL]
VI. INTRODUCTION [ITRO]
VII. STRUCTURE OF A VB PROGRAM [SVBP]
VIII. OUR FIRST PROGRAM [OFPR]
IX. STRING COMPARISON [STR1]
X. DECIPHERING A KEY GENERATOR [DKGN]
XI. CONCLUSION [END1][/font:3n85y0p4]
Last edited by vbgamer45 on Sat Feb 16, 2008 9:35 am; edited 13 times in total
|
|
Back to top |
|
|
|
_aLfa_ Site Admin
Joined: 21 Sep 2002 Posts: 233 Location: Aveiro, Portugal
|
Posted: Sat Feb 16, 2008 9:37 am
Post subject: I. DISCLAIMER AND NOTICE [DISN]
|
|
[font=Courier New:3rjaqmlq]This tutorial is meant for educational purposes only.
If the Reader chooses to break Protection Mechamisms after reading this
tutorial, he/she shall alone be responsible for the damages caused and not the
Author.
If you wish to post portions of this tutorial on a WebSite, you are free to do
so as long as you abide by these rules:
-> Post the selected portion in unedited form.
-> Mention the Author's Name,Email Address and Name of this tutorial above or
below the selected text.
-> Inform the Author.
The Author has not copied text or any other information directly from a Source.
However, some information from some sources has been used to write this tutorial.
These Sources have been mentioned in the References Section.
You are permitted to continue reading the tutorial only if you agree to the text
given above.[/font:3rjaqmlq] _________________ One thing only I know, and that is that I know nothing. (Socrates)
|
|
Back to top |
|
|
|
_aLfa_ Site Admin
Joined: 21 Sep 2002 Posts: 233 Location: Aveiro, Portugal
|
Posted: Sat Feb 16, 2008 9:39 am
Post subject: II. READING THIS TUTORIAL [RTUT]
|
|
[font=Courier New:33gobve0]Each Section in this Tutorial has a specific Topic Code enclosed in square
brackets. This arrangement has been made so that you can jump to a specific
topic simply by searching for the topic code from your Browser.
At many places in the tutorial, I've explained a few things which are almost
unnecessary to know when dealing with Visual BASIC programs but I've written
them for those who have a thirst for knowledge.
The Topic Code Tags [XTRA] and [/XTRA] have been given for "extra-information"
sections and you are free to skip them.
Text within the [XTRA]...[/XTRA] blocks is given for extra information.
You can search for the Extra Information using the Topic Code.[/font:33gobve0] _________________ One thing only I know, and that is that I know nothing. (Socrates)
|
|
Back to top |
|
|
|
_aLfa_ Site Admin
Joined: 21 Sep 2002 Posts: 233 Location: Aveiro, Portugal
|
Posted: Sat Feb 16, 2008 9:40 am
Post subject: III. ASSUMPTIONS [ASPT]
|
|
[font=Courier New:20u0py9q]You are required to have a basic understanding of:
: Visual BASIC
: C/C++
: Win31 API
: 80x86 Microprocessor Assembly Language.[/font:20u0py9q] _________________ One thing only I know, and that is that I know nothing. (Socrates)
|
|
Back to top |
|
|
|
_aLfa_ Site Admin
Joined: 21 Sep 2002 Posts: 233 Location: Aveiro, Portugal
|
Posted: Sat Feb 16, 2008 9:41 am
Post subject: IV. REQUIRED TOOLS AND DOCS [RQRT]
|
|
[font=Courier New:237984rc]You will need the following tools to proceed with the Tutorial.
: COMPILER : Visual Basic 6.0
: DISASSEMBLER : IDA Pro 4.x or higher
: DEBUGGER : OllyDebug Ver. 1.09d or higher
: WINDOWS API DOCUMENTATION
You can also use these tools for your own experiments.
: NuMeGa SmartCheck 6.x -> A Good VB Debugger with lots of features.
: VBDE version 0.85 by iorior -> gives offsets of VB procedures
: VBReformer -> can change properties of VB Controls
You can refer to API Documentation from MSDN or you can use the
API Text Viewer Tool supplied with Visual Studio or browse
MSDN Online (msdn.microsoft.com).
Certain Applications like APIViewer 2004 will also do.
It would be advisable to have a copy of Intel's 80x86 Instruction Set Manual.
Intel provides this manual free of charge.
The Software Developer's Manual consists of 3 volumes:
: Basic Architecture - Order Number 243190
: Instruction Set Reference - Order Number 243191
: System Programming Guide - Order Number 243192
You can obtain these manuals at http://developer.intel.com
I have given the names of the Tools that I have used. But you are free to use
any disassembler and debugger as long as you are comfortable using it but I
advice you to use the tools that I have used above. SoftIce is better than
OllyDebug but the latter is good enough so it doesn't matter which one you use.
But I strongly recommend the use of IDA Pro as it's the best disassembler that I
have seen so far.
--------------------------------------------------------------------------------
My First Version of this Tutorial got me a lot of comments and emails from
people reminding me of all the advantages of VB. They've told me not to overlook
the advantages of VB and that there is a reason why VB is slow.
I agree with them. Looks like I was focussed on only VB's shortcomings I guess.
In this tutorial, I wish to get things clear and let VB get the praise it
deserves.
--------------------------------------------------------------------------------[/font:237984rc] _________________ One thing only I know, and that is that I know nothing. (Socrates)
|
|
Back to top |
|
|
|
_aLfa_ Site Admin
Joined: 21 Sep 2002 Posts: 233 Location: Aveiro, Portugal
|
Posted: Sat Feb 16, 2008 9:44 am
Post subject: V. VB AS A LANGUAGE [VBAL]
|
|
[font=Courier New:3gkq1s72]It's like they say:"Everything has a reason."
After this section I am just going to focus on the internal details of Visual
BASIC and I just might say that the code generated by VB is pathetic. But before
I can do that, I want to ensure that you know the advantages that VB offers as
well.
I want to do this so that the next time you are writing an application, you can
decide whether or not to use Visual BASIC based on your priorities.
Visual BASIC is a well crafted language simply because learning to write code
doesn't take much time and yet VB is capable of generating Powerful Applications.
Many times when you don't have much time at your disposal, Visual Basic is the
best way to go as you can make your App do the same work (which another language
would let you do) in a shorter amount of time without compromising much on the
Application performance.
VB's library functions are DLL function calls to MSVBM60.DLL
Though this doesn't help in speeding up the App, it has a lot of advantages:
--> Core Code is written in the Runtime Files itself, making Visual BASIC
programs as small as possible.
--> Because of this architecture, the code is extremely easy to port to other
Windows Operating Systems. Consider this example.
--> VB does a lot of work by itself. C/C++ and other languages would require you
to write a lot of functions to even write a simple Windows Application.
[ THIS IS ONLY AN EXAMPLE. IT MAY NOT BE NECESSARILY TRUE ]
Suppose an API Function APIFunc() that exists in a DLL file in Windows XP is
removed from Windows Vista but Microsoft decides to include an alternate
function and names it AlternateAPIFunc() and puts it in another DLL file.
(Assuming all parameters and return value contents are the same)
We plan to write this in C.
Now comes the problem.
If we wish to use our app to work in Windows XP, we need to use the the function
APIFunc() in our applications and if we want it to work on Windows Vista we have
to replace every APIFunc() function call in our app to AlternateAPIFunc().
Isn't it cumbersome and tiring?
Now if we decide to use VB.
We continue to use the same code.
VB Functions call API Functions from the Runtime Files.
So nothing needs to be done because Windows XP will have a seperate set of
runtime files using the APIFunc() Function while the Vista Runtime Files would
use the AlternateAPIFunc() Function.
Doesn't that make the programmers job much much easier?
This is based on the Java portability technique where the Runtime Files of
Windows OS's can be thought of like Java Virtual Machines.
VB also includes support for Memory Handling and Stack Checks which otherwise
would have to be done manually by the programmer in another language.
So What I'm saying is all these features cost you on performance. But the
relative lag in performance is ingorable as the advantages outperform VB's
shortcomings.
So what follows below is just having a look at VB's Code Generation results and
Runtime Files code.
So when I talk about some code being inefficient, remember that it is so because
of the advantages that VB offers.
The topic of this tutorial concerns disassembling VB Applications and I will
look at only the Assembly code without being concerned of how VB is at the user
level.
Once you are clear about this, go ahead.
Please don't mail me stating that I could not appreciate the features of VB and
things like that.[/font:3gkq1s72] _________________ One thing only I know, and that is that I know nothing. (Socrates)
|
|
Back to top |
|
|
|
_aLfa_ Site Admin
Joined: 21 Sep 2002 Posts: 233 Location: Aveiro, Portugal
|
Posted: Sat Feb 16, 2008 9:48 am
Post subject: VI. INTRODUCTION [ITRO]
|
|
[font=Courier New:3aqknso5]If you have disassembled programs written in C/C++ or Pascal before, you would
know that it is not difficult to understand what the assembly instructions are
trying to achieve. These Languages generate neat,well written code and hence are
easier to read and comprehend when they are disassembled.
Try disassembling a program written in Visual BASIC. Most Disassemblers fail to
disassemble these programs because they assume that the structure of the
executable file is similar to that of C/C++ compiled programs.
Hence many people think that it is extremely difficult to disassemble and
understand programs written in Visual BASIC. However it is not so.
The executable file structure is entirely different in Visual Basic programs.
Once we get to know how Object data, strings and functions are stored and how
events are implemented then comprehending Disassembled Listings of Visual Basic
programs gets a lot easier.
So this tutorial does just that. Along with that it also gives ample proof to
show why Visual BASIC is never used by experts to write Fast and efficient code.
You will see in later examples why programs generated by Visual BASIC are slow.
The Tutorial will talk about executable files compiled in Visual BASIC in
Native Code and not p-code.
After reading this tutorial, you should be able to disassemble,debug and
understand Visual Basic Applications. You may also be able to reverse engineer
Protection Mechanisms written in Visual BASIC and by doing that you are putting
yourself to risk and not the author.
So now that you know what to expect from this tutorial, let's go ahead.[/font:3aqknso5] _________________ One thing only I know, and that is that I know nothing. (Socrates)
|
|
Back to top |
|
|
|
_aLfa_ Site Admin
Joined: 21 Sep 2002 Posts: 233 Location: Aveiro, Portugal
|
Posted: Sat Feb 16, 2008 9:50 am
Post subject: VII. STRUCTURE OF A VB PROGRAM [SVBP]
|
|
[font=Courier New:1zg7o4mv]When you open a VB Program in IDA, you'll end up with the following code.
start:
push offset dword_4012B4
call ThunRTMain
; ---------------------------------------------------------------------------
dd 0, 300000h, 400000h, 0, 0E9960000h, 82E6FCDFh, 939C4C23h
dd 0EB969B2Fh, 73D5h, 0, 1, 34303230h, 72503033h, 63656A6Fh
; etc etc etc
This doesn't make any sense does it? If you keep scrolling further you will see
sections of code and data. Each Section has a meaning in VB Programs and you can
see a general idea of a Visual BASIC program's Section Map below.
00401000:
... IAT (First Thunk ok apis)
Next Section(NS):
... some data
NS:
... transfer area (Jumps to imported functions)
NS:
... lots of data
NS:
... local transfer area (for internal event handlers)
NS:
... other data
NS:
... code
NS:
... lots of data
NS:
... .data Section
Let us now start analysis from the entry point of the program.
push offset RT_Struct
call ThunRTMain
It's C equivalent would have been:
ThunRTMain(&RT_Struct);
A function ThunRTMain is called which accepts one parameter. We'll soon find out
that the parameter is a structure.
Simply putting a step over command on the CALL statement results in the
execution of the Application.
Wierd Isn't it?
For Pascal,C and C++ Programs there is always a start() function that takes all
CommandLine Parameters,Gets ProcessThreads,Module Handles etc. We didn't see
anything of the sort in a Visual BASIC Program.
But actually, VB does have a start function. The start function code is placed
in the ThunRTMain Function. Let's verify that by disassembling the MSVBM60.DLL
and viewing the ThunRTMain Function. I've mentioned only a part of the
ThunRTMain Function Code.
ThunRTMain proc near
arg_0 = dword ptr 8
mov esi, [ebp+arg_0]
mov dword_7352F7DC, esi
and [ebp+var_4], 0
lea eax, [ebp+StartupInfo]
push eax ; lpStartupInfo
lea eax, [ebp+StartupInfo]
push eax ; lpStartupInfo
call ds:GetStartupInfoA
movzx eax, [ebp+StartupInfo.wShowWindow]
mov dword_7352F7D8, eax
push hModule
push esi
mov esi, offset dword_7352F470
mov ecx, esi
call sub_7342DECD
mov [ebp+var_1C], eax
test eax, eax
jl short loc_7342DEC5
push 0 ; lParam
push 0 ; wParam
push 1069h ; Msg
call ds:GetCurrentThreadId
push eax ; idThread
call ds:PostThreadMessageA
; Other Code
or [ebp+var_4], 0FFFFFFFFh
push 0 ; uExitCode
call ds:ExitProcess
jmp loc_734619B3
loc_7342DEC5: ; CODE XREF: ThunRTMain+60j
push eax
call sub_Free_Memory
jmp short loc_7342DEB4
endp
As you can see, it does call all the Functions that the start() function does in
C and PASCAL programs. But what about CommandLine() Function from KERNEL32.DLL?
MSVBM60.DLL does call that function as well but that function call is placed in
deeply nested function calls. You can open the Imports Window to see the
Imported Function and see the cross-reference to a procedure in MSVBM60.DLL
The sub_Free_Memory procedure calls various API Functions but if you keep
reading the procedure, you'll soon come across the HeapFree() Function which is
imported from kernel32.dll.
Now I guess you now know the purpose of the ThunRTMain Function.
Let us now see what structure is passed to it.
If we double-click on the RT_Struct offset, we reach an address containing
certain values.
It is a huge structure and each part needs to be seen one at a time.
Explaining the Structure will take up a lot of time and since I want to focus on
the Code Constructs of Visual BASIC, I won't entirely explain the Structure
passed to ThunRTMain.
We shall discuss the contents of this structure a little later.
I would also suggest you to read the article
"VISUAL BASIC REVERSED - A decompiling approach" by Andrea Geddon as it
does talk about the Structure passed to ThunRTMain in detail.[/font:1zg7o4mv] _________________ One thing only I know, and that is that I know nothing. (Socrates)
|
|
Back to top |
|
|
|
_aLfa_ Site Admin
Joined: 21 Sep 2002 Posts: 233 Location: Aveiro, Portugal
|
Posted: Sat Feb 16, 2008 9:53 am
Post subject: VIII. OUR FIRST PROGRAM [OFPR]
|
|
[font=Courier New:345xlxhe]Create a Form with a CommandButton. Click the CommandButton and add a simple
Msgbox Code as shown below:
Private Sub Command1_Click()
Msgbox "Ssup"
End Sub
Open the Compiled EXE File with IDA Pro.
Click the Strings Tab to find the "Ssup" String.
Double-Click the String to find its cross-reference.
Scroll up to the top of the procedure.
You should see something like this:
[Explanation is partly given by comments after an instruction.]
Command1_Click proc near
var_64 = dword ptr -64h
var_5C = dword ptr -5Ch
var_54 = dword ptr -54h
var_4C = dword ptr -4Ch
var_44 = dword ptr -44h
var_3C = dword ptr -3Ch
var_34 = dword ptr -34h
var_2C = dword ptr -2Ch
var_24 = dword ptr -24h
var_14 = dword ptr -14h
var_C = dword ptr -0Ch
var_8 = dword ptr -8 ; Destructor Object
var_4 = dword ptr -4
form_object = dword ptr 8
push ebp ; These two instructions
mov ebp, esp ; open the Stack Frame.
sub esp, 0Ch ; Allocates 12 bytes on stack
push (offset exception_handler+1); Starts Exception Handler
mov eax, large fs:0
push eax
mov large fs:0, esp
sub esp, 88h ; Allocates 136 bytes on stack
push ebx
push esi ; Saves Values of Registers
push edi
; Loads the Destructor
mov [ebp+var_C], esp
mov [ebp+var_8], offset destructor
; Allocating Dynamic Resources
mov eax, [ebp+form_object]
mov ecx, eax
and ecx, 1
mov [ebp+var_4], ecx
and al, 0FEh
push eax
mov [ebp+form_object], eax
mov edx, [eax]
call dword ptr [edx+4] ; Calls MSVBM60.Zombie_AddRef
mov ecx, 80020004h
xor esi, esi
mov [ebp+var_4C], ecx
mov eax, 0Ah
mov [ebp+var_3C], ecx
mov [ebp+var_2C], ecx
mov [ebp+var_34], esi
mov [ebp+var_44], esi
mov [ebp+var_54], esi
mov [ebp+var_64], esi
lea edx, [ebp+var_64]
lea ecx, [ebp+var_24]
mov [ebp+var_24], esi
mov [ebp+var_54], eax
mov [ebp+var_44], eax
mov [ebp+var_34], eax
mov [ebp+var_5C], offset aSsup ; "Ssup"
mov [ebp+var_64], 8
call ds:__vbaVarDup
lea eax, [ebp+var_54]
lea ecx, [ebp+var_44]
push eax
lea edx, [ebp+var_34]
push ecx
push edx
lea eax, [ebp+var_24]
push esi
push eax
call ds:rtcMsgBox ; Calls the MsgBox Function
lea ecx, [ebp+var_54]
lea edx, [ebp+var_44]
push ecx
lea eax, [ebp+var_34]
push edx
lea ecx, [ebp+var_24]
push eax
push ecx
push 4
call ds:__vbaFreeVarList
add esp, 14h
mov [ebp+var_4], esi
push offset continue_after_jump
jmp short fake_a_call_instr
lea edx, [ebp+var_54]
lea eax, [ebp+var_44]
push edx
lea ecx, [ebp+var_34]
push eax
lea edx, [ebp+var_24]
push ecx
push edx
push 4
call ds:__vbaFreeVarList
add esp, 14h
retn
; ---------------------------------------------------------------------------
fake_a_call_instr:
retn
; ---------------------------------------------------------------------------
continue_after_jump:
mov eax, [ebp+arg_0]
push eax
mov ecx, [eax]
call dword ptr [ecx+8] ; Calls MSVBM60.Zombie_Release
mov eax, [ebp+var_4]
mov ecx, [ebp+var_14]
pop edi
pop esi
mov large fs:0, ecx
pop ebx
mov esp, ebp
pop ebp ; Closes Stack Frame
retn 4
Command1_Click endp
Simply by looking at the entire procedure you can't exactly figure out what the
hell happens when the whole subroutine is executed. If you know Assembly well
and have had the patience to read through the code, you should notice a few neat
things in the code.
[XTRA]
Before I begin explaining the procedure, I want to teach you how to recognise a
procedure in Visual BASIC. They can be called Procedure Signatures.
1) A Procedure has the open and close Stack Frame instructions.
2) The First Procedure in a VB Program is always preceded by
12 0xCC Bytes (which corresponds to the INT 3 Instruction) followed by
4 'T' bytes (0xE9) followed by 12 0xCC bytes.
3) Procedures other than the first are preceded by 10 NOP(0x90) Instructions.
: 1) STACK FRAME:
The Open/Close Stack Frame Instructions are even found in C/C++ and Pascal
programs and hence can be termed as a universal method of determining procedures.
However that is not always the case.
--> Many compilers just JMP instructions to fake a Call Instruction. This Jump
is at times a CALL to a procedure. IDA Pro does not detect such
CALL 'emulating' instructions but OllyDebug does recognise such
code patterns.
--> Visual C++ allows the programmer to write naked functions. Naked functions
mean that the compiler does not allocate space for its arguments nor does it
include the stack open and close frame instructions.
But since we are dealing with Visual BASIC, we can ignore the second case. You
will see an example of the first case shortly.
: 2) THE 0xCC BYTE
The 0xCC Byte is used to Generate the INT 3 Exception, which is known as the
"CALL TO INTERRUPT" Procedure. It is used by Debuggers such as OllyDebug and
SoftIce to set software Breakpoints. Debuggers insert the 0xCC byte before the
instruction which it wants to set a breakpoint on. As soon as the INT 3
Instruction is executed, Control is passed onto the Debuggers Exception Handler.
Here is the description taken directly from Intel's Software Developers Manual
Volume 2 : Instruction Set Reference.
"The INT 3 instruction generates a special one byte opcode (CC) that is intended
for calling the debug exception handler. (This one byte form is valuable because
it can be used to replace the first byte of any instruction with a breakpoint,
including other one byte instructions, without over-writing other code). To
further support its function as a debug breakpoint, the interrupt generated with
the CC opcode also differs from the regular software interrupts as follows:
• Interrupt redirection does not happen when in VME mode; the interrupt is
handled by a protected-mode handler.
• The virtual-8086 mode IOPL checks do not occur. The interrupt is taken without
faulting at any IOPL level."
That's how debuggers work. That's also the concept of certain anti-debugging
techniques. Since the 0xCC code is injected by Debuggers before an instruction,
the CRC (Cyclic Redundancy Check) Value of the code also changes. Some
Antidebugging techniques encrypt the program with a key which is the CRC value
of the program. When a program is being debugged, its CRC value changes and with
the result the program doesn't get decrypted.
Such methods are effective in stopping amateur wannabe hackers from
understanding their code but its not foolproof and an expert hacker can get past
this technique with ease.
So much for what '0xCC' is. But why is it placed before the First Procedure in
VB Programs?
I've found no answer to that so far. This wastes a lot of space in a program.
If you try to disassemble a Console Program written in Visual C++, you'll find
many instructions which set parts of the stack to the '0xCC' value. You will
also find 0xCC bytes scattered across the disassembled listing.
If only Visual Studio was Open Source, we could have seen the code generation
code and come up with an answer and improve the code generation code too.
I hope you also realise why Open Source is slowly gaining momentum.
3) The 0x90 Byte
Here is the description taken directly from Intel's Software Developers Manual
Volume 2 : Instruction Set Reference.
"Performs no operation. This instruction is a one-byte instruction that takes up
space in the instruction stream but does not affect the machine context,
except the EIP register.
The NOP instruction is an alias mnemonic for the XCHG EAX, EAX instruction."
This byte is injected into serial generation/checking procedures by amateur
hackers where the protection mechanism is weak. This is known as bit-hacking.
Sadly enough, bit-hacking STILL works for defeating plenty of today's Commercial
Applications. Guess they never realised the importance for code-security.
While writing programs in Assembly Language, if you use Forward Referencing in a
few situations or use a wrong Jump Instruction to jump to certain addresses,
chances are quite bright that the Assembler will fill in some bytes with the NOP
instruction.
As a result, having the presence of the 0x90 Instruction in your code is
considered bad programming.
But again, I see no reason why the 0x90 Byte is present in Visual BASIC.
Removing such entries will reduce the executable size drastically.
Programs like VBDE rely on such Procedure Signatures to identify where a
procedure is present.
[/XTRA]
Let us start by analyzing the procedure in portions.
First the Procedure opens the Stack Frame. Then it allocates 12 Bytes on the
stack for the Destructor and other variables. ( We shall see the Destructor in
detail after a short while. )
Then it allocates Dynamic Resources and calls the Zombie_AddRef Function.
Zombie is a state in which the only valid consumer action on a COM object is
generally to release that object.
Here is the description of the use of Zombie_Addref and Zombie_Release Functions
from MSDN.
[XTRA]
The first three methods in a COM interface are required to be the same for all
COM interfaces. These are the methods of the IUnknown interface:
QueryInterface, AddRef, and Release.
The QueryInterface method takes an interface ID (an IID) and returns the
requested COM interface on the same object. The set of interface IDs
accessible via QueryInterface is the same from every interface on the object.
Each interface has a nominal reference count associated with it.
When a piece of code receives an interface, it should assume the reference count
is notionally 1 unless it has other knowledge.
AddRef increments the count, Release decrements it.
When the client has made one more call to Release than to
AddRef (meaning that the nominal count is zero), then it must assume that the
interface pointer is invalid. The provider of the interface may choose to
invalidate the interface pointer at that point (or not), but not before.
Some implementations have more relaxed behavior (for example, sharing
reference counts for all interfaces and/or only invalidating interface pointers
when the object is freed), but such behavior is not required, and should
certainly not be depended on. Although AddRef and Release return a ULONG, the
value returned is not required to have any meaning. Client code should not
depend in any way on the value returned. It exists solely for debugging code
to use, typically to return the new object reference count.
The reference-counting rules are very simple. When a client calls a member
function and passes one or more interface pointers:
The callee should AddRef its interface parameters if it wants them to stay around after it has gone.
The caller should Release the callee's returned interfaces when it
is done with them.
A straightforward consequence of the above rules is that QueryInterface does
an implicit AddRef on the returned interface, as do the
application programming interfaces (APIs) that create objects,
such as CoCreateInstance.
[/XTRA]
After reading the text above, you would understand why the AddRef and Release
Functions are present.
What does the Zombie_AddRef Function do? It Takes the Object Reference.
In this function the parent object (in this case Form) is passed as a parameter
and uses AddRef to increment reference count of the object (instantiation).
Since COM objects are responsible for their lifetime, the resources they use are
allocated until the reference count is 0, when it reaches 0 the objects enter
zombie state & can be deallocated to free resources.
Refer COM object management documentation for more detailed information.
Right after the call of the Zombie_AddRef Function there are MOV instructions
which assigns values to many variables. That follows a reference to the "Ssup"
string followed by a call to the rtcMsgbox procedure.
Why does it seem so wierd? Shouldn't it simply call the rtcMsgbox Function?
No, because it is a requirement to call QueryInterface,AddRef and Release
functions in Applications using COM Technology.
Now about the rtcMsgbox function.
Intuition tells us that no matter what the function does, it will end up calling
the MessageBoxA or the MessageBoxW Function. So let's set a breakpoint on the
MessageBoxA and MessageBoxW Functions.
To do that, start OllyDebug and load the Executable file by pressing F3.
After the program is loaded, press Alt+E to open the Executable Modules Window.
Double click USER32.DLL to open the disassembled listing of the User32.dll file.
From there press Ctrl+N to open the Imports/Exports Window. Then Scroll over
till you see the MessageBoxA and MessageBoxW Functions. Click them one at a time
and press F2 to set a breakpoint.
Now press F9 to run the program. The Application should open. Click the
CommandButton. Now instead of the Debugger halting at a breakpoint of MessageBox,
the MessageBox comes up without any halt to the Debugger.
Why does this happen? Does this mean that rtcMsgBox has a seperate copy of the
MessageBox code within itself? Though it seems like a possible reason, it is
unlikely to happen as Microsoft Developers built the Windows API so that they
could be reused for performance. So that means that some API Function is called
which displays the MessageBox.
So let us try another experiment. In the same Imports/Exports Section of
User32.dll we see 2 more MessageBox functions which are MessageBoxIndirectA and
MessageBoxIndirectW. Let's try setting a breakpoint on both these Messages.
After the breakpoint is set, press F9, and click the Command Button.
This time, the Debugger halts at the MessageBoxIndirectA function.
Interesting isn't it? All Visual BASIC Applications which use the Msgbox()
Function are actually calls to MessageBoxIndirectA and not MessageBox as thought.
This is an important characteristic. So the Next time you set a breakpoint on
the MessageBox function and the debugger halts at a breakpoint, you can be
pretty sure that someone has used the MessageBox() API Directly by consulting
the API Text Viewer for the VB Declaration.
Let us now see the prototype of the MessageBoxIndirect() API Function.
Private Declare Function MessageBoxIndirect Lib "user32" Alias
"MessageBoxIndirectA" (lpMsgBoxParams As MSGBOXPARAMS) As Long
Only One Parameter? So then how is the Message Body and Title passed to the
Function? For that we'll need to see the declaration of the MSGBOXPARAMS
Structure.
Private Type MSGBOXPARAMS
cbSize As Long
hwndOwner As Long
hInstance As Long
lpszText As String
lpszCaption As String
dwStyle As Long
lpszIcon As String
dwContextHelpId As Long
lpfnMsgBoxCallback As Long
dwLanguageId As Long
End Type
This suggests that the required parameters are assigned to variables and the
reference to that object is passed to that function.
So That suggests that the many MOV instructions found before the rtcMsgbox call
are used to initialise the MSGBOXPARAMS Structure.
To confirm our doubt, let's compare the MOV instructions with the code found
before the MessageBoxIndirect function is called.
mov edx, [eax]
mov [ebp+hWnd.lpszText], ecx
mov ecx, [eax+8]
mov eax, [eax+0Ch]
push esi
push ebx
test ah, 40h
mov [ebp+hWnd.hInstance], edi
mov [ebp+hWnd.lpszIcon], edi
mov [ebp+hWnd.lpfnMsgBoxCallback], edi
mov [ebp+hWnd.cbSize], 28h
mov [ebp+hWnd.hwndOwner], edx
mov [ebp+hWnd.lpszCaption], ecx
mov [ebp+hWnd.dwStyle], eax
mov [ebp+hWnd.dwLanguageId], edi
jz short loc_734A6133
mov [ebp+hWnd.lpfnMsgBoxCallback], offset sub_734A6098
loc_734A6133:
mov esi, ds:MessageBoxIndirectA
lea eax, [ebp+hWnd]
push eax ; LPMSGBOXPARAMSA
call esi ; MessageBoxIndirectA
Interesting to see that....Isn't it?
Next comes the __vbaFreeVarList Function. From its name we can see that it
deallocates the address of a certain number of variables. This function actually
does no work except call the __vbaFreeVar Function multiple number of times.
Let us see how both functions work.
__vbaFreeVar : Frees a Temporary Variable.
__vbaFreeVar accepts only 1 Argument, which is the address of the variable to be
deleted. This argument is ALWAYS passed through ECX.
Uses the API Function __imp_SysFreeString()[Ordinal Number 6] from OLEAUT32.DLL
that carries out the actual deallocation of a variable.
__vbaFreeVarList : Frees Temporary Variables.
Have a look at this Snippet:
lea ecx, [ebp+var_54] ; Variable 1 stored in ecx
lea edx, [ebp+var_44] ; Variable 2 => edx
push ecx ; Variable 1 pushed
lea eax, [ebp+var_34] ; Variable 3 => eax
push edx ; Variable 2 pushed
lea ecx, [ebp+var_24] ; Variable 4 => ecx
push eax ; Variable 3 pushed
push ecx ; Variable 4 pushed
push 4 ; Free 4 Temp. Variables
call ds:__vbaFreeVarList
The code is pretty easy to understand. This function frees temporary variables
that are passed as arguments to it.Interestingly each memory location is
16 bytes wide.
This is an interesting function as it can accept variable arguments.
It's equivalent function call in C would be:
__vbaFreeVarList(4,&var_24,&var_34,&var_44,&var_54);
where its declaration would be:
int __vbaFreeVarList(int NUMBER_OF_VARIABLES_TO_FREE,<addresses of the vars>...)
{
// CODE
}
If we analyse the code of __vbaFreeVarList, we actually find multiple calls of
__vbaFreeVar. Have a look at the source code of __vbaFreeVarList.
public __vbaFreeVarList
__vbaFreeVarList proc near
arg_0 = dword ptr 4
arg_4 = dword ptr 8
arg_8 = dword ptr 0Ch
mov ecx, [esp+arg_4] ; Address of Variable to delete
push esi ; Saves value of esi
lea esi, [esp+4+arg_8] ; esi = Address of Next Variable
call __vbaFreeVar ; function call
mov eax, [esp+arg_4] ; eax gets value of num of
; variables to be freed
cmp eax, 1 ; If eax<=1 then
jbe short freed_all_vars ; jump to end of function.
push edi ; Value of edi is saved on stack
lea edi, [eax-1] ; edi=eax-1
; THIS IS A WHILE LOOP : while(edi){ /*CODE*/ }
loop_start:
mov ecx, [esi] ; ecx=Address of Variable to Delete
add esi, 4 ; esi = Address of Next Variable
call __vbaFreeVar ; function call
dec edi ; edi--;
jnz short loop_start ; Jump to beginning of the loop if
; edi is not ZERO.
; Well Written Code.No need for a
; CMP Instruction as DEC
; Instruction affects the ZERO Flag
pop edi ; Value of edi is restored.
freed_all_vars:
pop esi ; Value of esi is restored.
retn ; Return to the calling function
ENGINE:7352009D __vbaFreeVarList endp
As you can see, __vbaFreeVarList uses a while loop to free each variable one by
one using the __vbaFreeVar Function.
Notice that the address of the variable to be freed is stored in ECX always.
You can disassemble the __vbaFreeVar Function to confirm that.
Now let us see what happens when after the MessageBox is shown.
This is the most interesting part.
After the MessageBox is displayed, a clean up code is executed that deallocates
all the variables used in the entire procedure. Have a look at these statements
in the Command1_Click() Code.
push offset continue_after_jump
jmp short fake_a_call_instr
; ---------------------------------------------------------------------------
fake_a_call_instr:
retn
; ---------------------------------------------------------------------------
continue_after_jump:
; code
This is the 'CALL-Simulation' instruction. If you recall, before a call function
is executed, the processor pushes the location of the instructions which are
supposed to receive control after execution of a function is over.
VB instead of issuing a call instruction simulates it using the push, jmp and
retn instructions. It is small sections of code like this that reduce Visual
BASIC's efficiency and performance.
Let us still see why this is done.
The CALL-Simulation Instruction calls the MSVBM60.Zombie_Release function.
This is the destructor code. Doesn't that remind you of something?
The instruction
mov [ebp+var_8], offset destructor
contains the offset of the destructor code. But is this so?
Double-click on the 'offset destructor' text and you'll land up here.
destructor dd 80005h, offset loc_401A7E, 0, offset loc_401A85, 102825FFh
Hmm...this contains more offsets? By simply double-clicking the offsets you land
up at the destructor code again. That's why the CALL simulation code is used so
that the destructor code looks like its an inline function.
If you're more curious, you can also double-click the 'exception_handler' text
to see where that leads to.
Well, after a long journey into the Command1_Click() Procedure, we're finally
done analyzing it.
From this point onwards, I shall explain only the important section of code
rather than explain such intricate details once again.
Let us proceed further.
This Time let us create a Visual BASIC Application using only a module.
We shall use the Main Subroutine.
Use this code:
Sub Main()
MsgBox "Ssup"
End Sub
What you will realise that the Procedure code is an exact copy of the code we
dealt with earlier. This means that Form Procedures and Module Procedures are
treated alike. This also means that the Command Button code procedure had no
chance of using any information of the Form Object.[/font:345xlxhe] _________________ One thing only I know, and that is that I know nothing. (Socrates)
|
|
Back to top |
|
|
|
_aLfa_ Site Admin
Joined: 21 Sep 2002 Posts: 233 Location: Aveiro, Portugal
|
Posted: Sat Feb 16, 2008 10:11 am
Post subject: IX. STRING COMPARISON [STR1]
|
|
[font=Courier New:31zlmlog]Create a form without any controls. The code in the form module is as follows:
Private Sub Form_Load()
If "Sanchit" <> InputBox("ssup") Then
MsgBox "wrong"
Else
MsgBox "Right"
End If
End Sub
The resultant code is shown below (after stripping irrelevant instructions)
Form_Load proc near
; Variables and Arguments shown
push ebp
mov ebp, esp
sub esp, 0Ch
push (offset vba_exception_handler+1)
mov eax, large fs:0
push eax
mov large fs:0, esp
sub esp, 0F0h
push ebx
push esi
push edi
mov [ebp+var_C], esp
mov [ebp+var_8], offset destructor
mov eax, [ebp+arg_0]
mov ecx, eax
and ecx, 1
mov [ebp+var_4], ecx
and al, 0FEh
push eax
mov [ebp+arg_0], eax
mov edx, [eax]
call dword ptr [edx+4] ; Zombie_AddRef()
xor eax, eax
mov ebx, 80020004h
mov edi, 0Ah
; code...
lea edx, [ebp+var_98]
lea ecx, [ebp+var_28]
; MOV [var],register Instructions
mov [ebp+var_90], offset aSsup ; "ssup"
mov [ebp+var_98], 8
call ds:__vbaVarDup
lea eax, [ebp+var_88]
push offset aSanchit ; "Sanchit"
lea ecx, [ebp+var_78]
push eax
lea edx, [ebp+var_68]
push ecx
lea eax, [ebp+var_58]
push edx
lea ecx, [ebp+var_48]
push eax
lea edx, [ebp+var_38]
push ecx
lea eax, [ebp+var_28]
push edx
push eax
call ds:rtcInputBox
mov edx, eax
lea ecx, [ebp+var_18]
call ds:__vbaStrMove
push eax
call ds:__vbaStrCmp
mov esi, eax
lea ecx, [ebp+var_18]
neg esi
sbb esi, esi
neg esi
neg esi
call ds:__vbaFreeStr
lea ecx, [ebp+var_88]
lea edx, [ebp+var_78]
push ecx
lea eax, [ebp+var_68]
push edx
lea ecx, [ebp+var_58]
push eax
lea edx, [ebp+var_48]
push ecx
push edx
lea eax, [ebp+var_38]
lea ecx, [ebp+var_28]
push eax
push ecx
push 7
call ds:__vbaFreeVarList
add esp, 20h
mov [ebp+var_50], ebx
test si, si
mov [ebp+var_58], edi
mov [ebp+var_40], ebx
mov [ebp+var_48], edi
mov [ebp+var_30], ebx
mov [ebp+var_38], edi
jz short jump_if_right
lea edx, [ebp+var_98]
lea ecx, [ebp+var_28]
mov [ebp+var_90], offset aWrong ; "wrong"
mov [ebp+var_98], 8
call ds:__vbaVarDup
lea edx, [ebp+var_58]
lea eax, [ebp+var_48]
push edx
lea ecx, [ebp+var_38]
push eax
push ecx
lea edx, [ebp+var_28]
push 0
push edx
call ds:rtcMsgBox
lea eax, [ebp+var_58]
lea ecx, [ebp+var_48]
push eax
lea edx, [ebp+var_38]
push ecx
lea eax, [ebp+var_28]
push edx
push eax
jmp short free_up_resources
; ---------------------------------------------------------------------------
jump_if_right:
lea edx, [ebp+var_98]
lea ecx, [ebp+var_28]
mov [ebp+var_90], offset aRight ; "Right"
mov [ebp+var_98], 8
call ds:__vbaVarDup
lea ecx, [ebp+var_58]
lea edx, [ebp+var_48]
push ecx
lea eax, [ebp+var_38]
push edx
push eax
lea ecx, [ebp+var_28]
push 0
push ecx
call ds:rtcMsgBox
lea edx, [ebp+var_58]
lea eax, [ebp+var_48]
push edx
lea ecx, [ebp+var_38]
push eax
lea edx, [ebp+var_28]
push ecx
push edx
free_up_resources:
push 4
call ds:__vbaFreeVarList
add esp, 14h
mov [ebp+var_4], 0
push offset call_emulate
jmp short jump_as_a_call
; ---------------------------------------------------------------------------
lea ecx, [ebp+var_18]
call ds:__vbaFreeStr
lea eax, [ebp+var_88]
lea ecx, [ebp+var_78]
push eax
lea edx, [ebp+var_68]
push ecx
lea eax, [ebp+var_58]
push edx
lea ecx, [ebp+var_48]
push eax
lea edx, [ebp+var_38]
push ecx
lea eax, [ebp+var_28]
push edx
push eax
push 7
call ds:__vbaFreeVarList
add esp, 20h
retn
; ---------------------------------------------------------------------------
jump_as_a_call:
retn
; ---------------------------------------------------------------------------
call_emulate:
mov eax, [ebp+arg_0]
push eax
mov ecx, [eax]
call dword ptr [ecx+8] ; Zombie_Release()
mov eax, [ebp+var_4]
mov ecx, [ebp+var_14]
pop edi
pop esi
mov large fs:0, ecx
pop ebx
mov esp, ebp
pop ebp
retn 4
Form_Load endp
Let us first see the Prototype of the InputBox Function
Function InputBox(Prompt As String, Title As String, Default as String , _
xpos As Long , ypos As Long, helpfile As String ,context As Long ) _
As String
If we disassemble the MSVBM60.DLL File and scroll over to the rtcInputBox
function, we can confirm this from the prototype that IDA provides us.
Most of the code is irrelevant to us but the important chunk of code of the
function (which took me quite some time to find) is given below:
push edi ; Context Pushed
push ebx ; HelpFile Pushed
push [ebp+arg_8] ; ypos Pushed
push [ebp+arg_C] ; xpos Pushed
push eax ; Default pushed
push ecx ; Title Pushed
push edx ; Prompt pushed
call sub_7349DC68 ; Function that causes Inputbox
; At this point EAX contains the entered string
push [ebp+arg_4] ; BSTR
mov edi, eax
call esi ; __imp_SysFreeString
push [ebp+arg_0] ; BSTR
call esi ; __imp_SysFreeString
push [ebp+var_4] ; BSTR
call esi ; __imp_SysFreeString
push [ebp+var_1C] ; BSTR
call esi ; __imp_SysFreeString
mov eax, edi ; Sets EAX to the Return Value
pop edi
pop esi
pop ebx
leave ; Close Stack Frame
retn 1Ch ; Returns from here
In the first portion of the code, the push instructions push all the seven
parameters to the function that creates the InputBox Dialogbox. I know that with
the current example that I'm disassembling, it's not quite possible to believe
that all the push instructions stand for what I've mentioned. So what you can do
is disassemble the following code given below and set a breakpoint on the PUSH
instructions in the MSVBM60.DLL File using OllyDebug or SoftIce.
str1 = InputBox("This is prompt","This is Title","Default-Val",10,20, _
"c:\help.hlp",1)
With this you can actually verify the contents of the push instruction to
confirm what I've written.
Now, after the call instruction you can see a PUSH instruction pushing the
contents of a variable. This is a parameter for the SysFreeString Function.
Next is a MOV instruction transferring the contents of the EAX register into EDI.
EAX at this point of time contains the address of the String that we filled in
the Text Box. This is done to save the value of EAX.
Then the SysFreeString Function is called. This function takes 1 argument which
is the string that needs to be deallocated. This function does not return any
value after execution.
Did you notice something?
If the SysFreeString Function does not return any value, then why were the
contents of EAX saved in EDI? And why is there a need to have a MOV EAX , EDI
instruction?
This might have been done on purpose to ensure that the original value of EAX is
not lost but maybe the developers didn't realize that it wasn't required in this
case. Whatever be the reason, it is a waste of precious bytes.
Anyway, the original contents of the registers are restored, the stack frame is
closed (with LEAVE) and the function returns after adding 0x1C bytes to ESP.
Now let's have a look at this code portion.
call ds:rtcInputBox
mov edx, eax
lea ecx, [ebp+var_18]
call ds:__vbaStrMove
push eax
call ds:__vbaStrCmp
mov esi, eax
lea ecx, [ebp+var_18]
neg esi
sbb esi, esi
neg esi
neg esi
call ds:__vbaFreeStr
After the call of rtcInputBox, EAX contains the entered string in the Text Box
of the InputBox dialog. The address of this string is moved to EDX.
Is this done to save the contents of the String for the compare function?
As obvious as it may seem, it is really not like that. Let us see.
The __vbaStrMove function moves a String from one place in memory to another
place. On Analysis of the function code it is found that this function accepts
two arguments and returns one value as shown below:
PARAMETERS:
EDX : Source String
ECX : Destination
RETURNS : Source String. Sets EAX to EDI (which holds value of EDX)
Now we see that by setting the value of EAX to EDX, we are setting the entered
string as a SOURCE string to be copied into another location. This is neat.
Now the Source String is pushed again and the __vbaStrCmp Function is called.
This on first glance looks wierd again. It seems that the StrCmp Function
accepts only one argument. Then what does it compare it with?
If you scroll above you will find a push instruction that pushes the address of
the string "Sanchit" ( push offset aSanchit ; "Sanchit" )
Such cases remind us that unlike code generated by Pascal and C/C++ compilers,
Visual BASIC functions can have it's arguments pushed anywhere and not right
before the function call.
Keep this thing in mind when you set out to disassemble your own Visual BASIC
programs.
Now after the Comparing function returns its value via the EAX register, it is
copied to ESI.
Then the LEA instruction is used to load the address of a variable in the ECX
register. Now since we are aware of VB's tricks we know that this is a parameter
to the __vbaFreeStr function. You should notice that the same variable which
held the value of the entered string is now being passed to this function to
deallocate it as its not required after the comparison has been done.
Now let's talk about this code fragment:
neg esi
sbb esi, esi
neg esi
neg esi
call ds:__vbaFreeStr
The NEG statement's actual use is to change the sign of a number for example,
from 3 to -3.
But this one has an indirect use. This Instruction affects many flags. But the
one it is meant for is the Carry Flag (CF) which is used in the next SBB
Instruction.If ESI is equal to 0 then CF is reset to 0 and otherwise is set to 1.
Now the SBB Instruction stands for Subtraction with Borrow. In this case it can
be translated to this:
ESI = ESI - (ESI + CF);
This is where the previous NEG instruction comes into picture.
The next two NEG instructions are of no use. You can take this as another
example to show why VB code is slow.
Following this is the __vbaFreeStr Function which deallocates space for a string
variable.
Now you might wonder that if comparison has been performed, then why isn't there
any JUMP instruction?
If you keep reading the code you will find the TEST and JUMP Instructions after
the seven variables used have been cleared. These instructions are found
together in C/C++ and Pascal programs but in Visual BASIC this isn't always the
case.
That's why Visual BASIC programs take up more time for analysis compared to C
and Pascal programs.
I'm not discussing the rest of the code as it has been covered in the previous
section.
Now let's discuss a Hack-tip.
This type of String Comparision protection is used in many popular Shareware
Applications.
Removing such protection isn't much of a job and I'll discuss a cleaner way to
hack this protection. (Refers to programs written in Visual BASIC)
Remember the two useless NEG instructions before the __vbaFreeStr Function call?
Since these instructions are of no practical use, we can replace these two bytes
with XOR ESI, ESI which consumes only 2 bytes. That way the TEST instruction
would always result in ZERO making control jump always to the Msgbox("Right")
code.
A lot of Hackers use such 'useless' code to implement such hacking techniques.
It is considered smart hacking instead of simply NOPing the bytes.[/font:31zlmlog] _________________ One thing only I know, and that is that I know nothing. (Socrates)
|
|
Back to top |
|
|
|
_aLfa_ Site Admin
Joined: 21 Sep 2002 Posts: 233 Location: Aveiro, Portugal
|
Posted: Sat Feb 16, 2008 10:14 am
Post subject: X. DECIPHERING A KEY GENERATOR [DKGN]
|
|
[font=Courier New:2oqg28s5]Let us now attempt to understand a simple key generation routine written in
Visual BASIC. Here is the code.
' Create TextBox with Name as txtname
' Create TextBox with Name as txtserial
' Create CommandButon with Name as cmdverify
Option Explicit
Private Sub cmdverify_Click()
Dim n As String ' Name
Dim s As String ' User entered serial
Dim v_serial As String ' Actual Serial
Dim tmp1 As Long
Dim i As Byte
n = txtname.Text
s = txtserial.Text
tmp1 = 0
For i = 1 To Len(n)
tmp1 = tmp1 + Asc(Mid(n, i, 1))
tmp1 = tmp1 * i
Next i
v_serial = Hex(tmp1)
If s = v_serial Then
MsgBox "Correct"
Else
MsgBox "Incorrect"
End If
End Sub
As you can see, this is really a simple Keygenerator. And you'll be surprised to
learn that a similar protection code is used in a Shareware Application that
exists even today.
So let's disassemble this file and see what VB generates out of our code.
The code mentioned below is that of the Click() Event of the cmdverify Button.
cmdverify_click proc near
len_entered_name= byte ptr -0C0h
var_temp2 = dword ptr -80h
msgbox_text = dword ptr -78h
var_70 = dword ptr -70h
var_68 = dword ptr -68h ; I've Simplified the Variable Names
var_60 = dword ptr -60h ; for Easier Understanding of their use.
var_58 = dword ptr -58h
var_50 = dword ptr -50h
var_48 = dword ptr -48h
var_temp = dword ptr -40h
var_38_use_unknown= dword ptr -38h
var_30 = dword ptr -30h
address_having_user_input_content= dword ptr -2Ch
serial_no_destination_address= dword ptr -28h
address_for_entered_serial= dword ptr -24h
keygen_sum = dword ptr -20h
address_for_entered_name= dword ptr -1Ch
saved_loop_counter= dword ptr -18h
var_14 = dword ptr -14h
var_C = dword ptr -0Ch
var_8 = dword ptr -8
var_4 = dword ptr -4
arg_0 = dword ptr 8
push ebp
mov ebp, esp ; Opening Stack Frame
sub esp, 0Ch
push offset vba_exception_handler
mov eax, large fs:0
push eax
mov large fs:0, esp
sub esp, 0BCh
push ebx
push esi
push edi
mov [ebp+var_C], esp
mov [ebp+var_8], offset destructor
mov esi, [ebp+arg_0]
mov eax, esi
and eax, 1
mov [ebp+var_4], eax
and esi, 0FFFFFFFEh
push esi
mov [ebp+arg_0], esi
mov ecx, [esi]
call dword ptr [ecx+4]
mov edx, [esi]
xor edi, edi ; edi = 0
push esi
mov [ebp+address_for_entered_name], edi
mov [ebp+keygen_sum], edi
mov [ebp+address_for_entered_serial], edi
mov [ebp+serial_no_destination_address], edi
mov [ebp+address_having_user_input_content], edi
mov [ebp+var_30], edi
mov [ebp+var_temp], edi
mov [ebp+var_50], edi ; Initializing all variables to ZERO
mov [ebp+var_60], edi
mov [ebp+var_70], edi
mov [ebp+var_temp2], edi
call dword ptr [edx+2FCh]
push eax
lea eax, [ebp+var_30]
push eax
call ds:__vbaObjSet
mov ebx, eax
lea edx, [ebp+address_having_user_input_content] ; Load Effective Address
push edx
push ebx
mov ecx, [ebx]
call dword ptr [ecx+0A0h] ; Call MSVBM60.7347Fd34
; Calls a function that allocates memory
cmp eax, edi ; Compare Two Operands
fnclex ; Clear Exceptions (no wait)
jge short jump_if_no_exception
; If (SF==0F) ie. No Exceptions Pending, goto
; main section of code
push 0A0h
push offset not_sure_what_this_is
push ebx
push eax
call ds:__vbaHresultCheckObj
jump_if_no_exception:
mov edx, [ebp+address_having_user_input_content]
; Now edx contains entered name(Source String)
lea ecx, [ebp+address_for_entered_name]
; ecx gets an address.(Destination String)
mov [ebp+address_having_user_input_content], edi
; Clear out user-entered-name from stack with NULL as edi contains NULL
call ds:__vbaStrMove ; Copies String from EDX to ECX
mov ebx, ds:__vbaFreeObj
lea ecx, [ebp+var_30] ; Address of object to clear
call ebx ; __vbaFreeObj ; Clears memory allocated by some object.
; fills address with null
; and returns 0 (Deallocation SUCCESSFUL)
mov eax, [esi] ; eax points to address 4032EC which is blank
push esi
call dword ptr [eax+300h] ; Goto 73520D1C Address in MSVBM60.Dll
lea ecx, [ebp+var_30] ; ecx gets address which was previously deallocated
push eax
push ecx
call ds:__vbaObjSet ; Initialises some object.
;
; Result of function:
; Eax value has been copied in the stack address of ecx
; No change in eax value;Shows that call has been made to a Sub
mov esi, eax ; Saves address of eax
lea eax, [ebp+address_having_user_input_content] ; eax gets stack address
push eax ; and pushed as parameter
push esi ; along with original value of eax
mov edx, [esi]
call dword ptr [edx+0A0h] ; Calls a Memory Allocation Subroutine
; Return Value 0 (NO_ERROR)
cmp eax, edi ; IF( 0 == 0 (edi is zero as well) )
fnclex ; Clear Exceptions without wait
jge short jump_if_no_exception2 ; Jump if Greater or Equal (SF=OF)
push 0A0h
push offset not_sure_what_this_is
push esi
push eax
call ds:__vbaHresultCheckObj
jump_if_no_exception2:
mov edx, [ebp+address_having_user_input_content]
; edx = User entered Serial (Source)
lea ecx, [ebp+address_for_entered_serial] ; Destination Address
mov [ebp+address_having_user_input_content], edi ;Erases the text from stack
; since edi is 0
; This strMove code is different from the previous one
; encountered. Previously, strmove was used to COPY
; the contents of a string.
; This time, it's being used to REPLACE/MOVE the contents
; of a string from 1 location to another.
;
; That is interesting. Strmove doing 2 different things.
call ds:__vbaStrMove
lea ecx, [ebp+var_30] ; Address to be freed
call ebx ; __vbaFreeObj ; and freed
; ie. address is filled with NULL
; and return value is 0 (SUCCESSFUL)
mov ecx, [ebp+address_for_entered_name] ;Gets user-entered-string from stack
mov [ebp+keygen_sum], edi ; Nulls a Stack Address.
; Possible Initialisation of variable
push ecx ; Pushes Entered-Name
call ds:__vbaLenBstr ; Calls the Len Function.
; Interesting how the function works.
mov ecx, eax ; ecx = Len(entered_name)
call ds:__vbaUI1I4 ; Checks if Length of String <=255 characters.
; If so, uses appropriate functions to get actual length
; or display overflow errors.
mov ecx, 1 ; ecx=1
; Takes 5 bytes.
; This Improvised code takes 3 bytes only:
; 2 bytes : xor ecx,ecx
; 1 byte : inc ecx
mov [ebp+len_entered_name], al ; Stores Length of entered_name in stack.
; After studying the below function,
; you'll realise why al and not ah,ax or eax was used
call ds:__vbaUI1I2 ; Uses ecx value to check same thing as
; __vbaUI14 does
; If ecx >255 then same procedure is done
mov edi, ds:__vbaFreeVarList
mov bl, al ; bl=1
mov byte ptr [ebp+saved_loop_counter], bl ; Sets the variable to 1
; We'll see why this value is saved in the stack
; once we study the loop
loop_begin:
cmp bl, [ebp+len_entered_name] ; Checks if bl <= Len(entered_name)
ja jump_end_of_loop ; If bl > Len(entered_name) then jump out of loop
mov esi, [ebp+saved_loop_counter] ; Sets ESI to Saved Loop Counter
lea edx, [ebp+address_for_entered_name]
;Gets address where entered name is located
lea eax, [ebp+var_temp] ; Gets address of a variable with NULL content
and esi, 0FFh ; esi &= 0xFF;
mov [ebp+msgbox_text], edx ; msgbox_text = **(edx);
; **edx happens to be the entered_name
push eax ; Argument 4 of Mid()
; PUSHES BLANK VARIABLE
lea ecx, [ebp+var_temp2] ; Gets address of a variable with NULL content
push esi ; Argument 3 of Mid()
; Pushes SAVED LOOP COUNTER
lea edx, [ebp+var_50] ; Gets address of a variable with NULL content
push ecx ; Argument 2 of Mid()
; PUSHES BLANK VARIABLE
push edx ; Argument 1 of Mid()
; PUSHES BLANK VARIABLE
mov [ebp+var_38_use_unknown], 1
mov [ebp+var_temp], 2
mov [ebp+var_temp2], 4008h
call ds:rtcMidCharVar ; Stores the extracted piece of string in an
; unknown location.
lea eax, [ebp+var_50] ; Has value 8
lea ecx, [ebp+address_having_user_input_content] ; Load Effective Address
push eax ; Pushes 8
push ecx ; Pushes empty variable
call ds:__vbaStrVarVal ; Gets the unknown location where the extracted
; string was put and returns the address.
push eax ; Pushes address of extracted character.
call ds:rtcAnsiValueBstr ; Asc(eax)
; Now AX contains ASCII Value
movsx edx, ax ; Extends AX into EDX
mov eax, [ebp+keygen_sum]
lea ecx, [ebp+address_having_user_input_content] ; Load Effective Address
add edx, eax ; Adds value of keygen_sum to the ASCII Value
; of the current character extracted and stores
; result of addition into edx.
jo jump_overflow ; Jump if Sum results in Overflow.
; VB doing Exception Checks....Nice.
mov [ebp+keygen_sum], edx ; Stores the sum back into the keygen_sum variable
call ds:__vbaFreeStr
lea eax, [ebp+var_50] ; Load Effective Address
lea ecx, [ebp+var_temp] ; Load Effective Address
push eax
push ecx
push 2
call edi ; __vbaFreeVarList
add esp, 0Ch ; Add
imul esi, [ebp+keygen_sum] ; Multiplies Keygen_sum with the Loop Counter
; and stores result in esi.
mov al, 1 ; Sets AL to 1
jo jump_overflow ; Jump if Multiplication results in overflow
add al, bl ; Adds 1 to Loop_counter stored in BL
; INC bl would have been a better way
; since implementation of incrementing loop counter
; would cost only 1 byte compared to current 4 bytes.
mov [ebp+keygen_sum], esi ; Stores Result of Multiplication into keygen_sum
jb jump_overflow ; Checks if loop counter increment doesn't cause an
; exception.
mov bl, al ; Sets Loop Counter value stored in al to bl
mov byte ptr [ebp+saved_loop_counter], bl ; Saves Loop Counter in Variable
jmp loop_begin ; Back to the loop
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
jump_end_of_loop:
lea eax, [ebp+var_temp2] ; Load Effective Address
lea ecx, [ebp+var_temp] ; Load Effective Address
lea edx, [ebp+keygen_sum] ; Gets Final Serial Number
push eax
push ecx
mov [ebp+msgbox_text], edx
mov [ebp+var_temp2], 4003h
call ds:rtcHexVarFromVar
lea edx, [ebp+var_temp] ; Load Effective Address
push edx
call ds:__vbaStrVarMove ; Returns Hex(String) in EAX
mov edx, eax ; Hex(Serial) is the Source
lea ecx, [ebp+serial_no_destination_address] ;ECX contains the Dest. Address
call ds:__vbaStrMove
lea ecx, [ebp+var_temp] ; Gets Var Address
call ds:__vbaFreeVar ; Frees it
mov eax, [ebp+address_for_entered_serial] ; Gets Address of Serial in EAX
mov ecx, [ebp+serial_no_destination_address] ; Gets Address of Valid Serial
push eax ; Pushes entered_serial
push ecx ; Pushes real Serial
call ds:__vbaStrCmp
test eax, eax ; Checks Return value of comparison
mov ecx, 80020004h
mov eax, 0Ah
mov [ebp+var_68], ecx
mov [ebp+var_70], eax
mov [ebp+var_58], ecx
mov [ebp+var_60], eax
mov [ebp+var_48], ecx
mov [ebp+var_50], eax
jnz short jump_incorrect_serial ; Jump if Incorrect Serial
lea edx, [ebp+var_temp2] ; Gets Destination Address
lea ecx, [ebp+var_temp] ; Gets Source Address
mov [ebp+msgbox_text], offset aCorrect ; "Correct"
mov [ebp+var_temp2], 8
call ds:__vbaVarDup ; No idea
lea edx, [ebp+var_70] ; Load Effective Address
lea eax, [ebp+var_60] ; Load Effective Address
push edx
lea ecx, [ebp+var_50] ; Load Effective Address
push eax
push ecx
lea edx, [ebp+var_temp] ; Load Effective Address
push 0
push edx
call ds:rtcMsgBox ; Call Msgbox()
lea eax, [ebp+var_70] ; Load Effective Address
lea ecx, [ebp+var_60] ; Load Effective Address
push eax
lea edx, [ebp+var_50] ; Load Effective Address
push ecx
lea eax, [ebp+var_temp] ; Load Effective Address
push edx
push eax
jmp short jump_end_function ; Jump
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
jump_incorrect_serial:
lea edx, [ebp+var_temp2] ; Load Effective Address
lea ecx, [ebp+var_temp] ; Load Effective Address
mov [ebp+msgbox_text], offset aIncorrect ; "Incorrect"
mov [ebp+var_temp2], 8
call ds:__vbaVarDup
lea ecx, [ebp+var_70] ; Load Effective Address
lea edx, [ebp+var_60] ; Load Effective Address
push ecx
lea eax, [ebp+var_50] ; Load Effective Address
push edx
push eax
lea ecx, [ebp+var_temp] ; Load Effective Address
push 0
push ecx
call ds:rtcMsgBox
lea edx, [ebp+var_70] ; Load Effective Address
lea eax, [ebp+var_60] ; Load Effective Address
push edx
lea ecx, [ebp+var_50] ; Load Effective Address
push eax
lea edx, [ebp+var_temp] ; Load Effective Address
push ecx
push edx
jump_end_function:
push 4
call edi ; __vbaFreeVarList
add esp, 14h
mov [ebp+var_4], 0
loc_401FE8:
push offset loc_402033 ; A CALL INSTRUCTION SIMULATION
jmp short free_and_then_simulate_call ; Jump
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
loc_401FEF:
lea ecx, [ebp+address_having_user_input_content] ; Load Effective Address
call ds:__vbaFreeStr
lea ecx, [ebp+var_30] ; Load Effective Address
call ds:__vbaFreeObj
lea eax, [ebp+var_70] ; Load Effective Address
lea ecx, [ebp+var_60] ; Load Effective Address
push eax
lea edx, [ebp+var_50] ; Load Effective Address
push ecx
lea eax, [ebp+var_temp] ; Load Effective Address
push edx
push eax
push 4
call ds:__vbaFreeVarList
add esp, 14h ; Add
retn ; Return Near from Procedure
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
free_and_then_simulate_call:
mov esi, ds:__vbaFreeStr ; Used Variables are cleared
ea ecx, [ebp+address_for_entered_name] ; Load Effective Address
call esi ; __vbaFreeStr
lea ecx, [ebp+address_for_entered_serial] ; Load Effective Address
call esi ; __vbaFreeStr
lea ecx, [ebp+serial_no_destination_address] ; Load Effective Address
call esi ; __vbaFreeStr
retn
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
loc_402033:
mov eax, [ebp+arg_0]
push eax
mov ecx, [eax]
call dword ptr [ecx+8] ; Call Zombie_Release()
mov eax, [ebp+var_4]
mov ecx, [ebp+var_14]
pop edi
pop esi
mov large fs:0, ecx
pop ebx
mov esp, ebp
pop ebp
retn 4 ; Return Near from Procedure
cmdverify_click endp
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
jump_overflow:
call ds:__vbaErrorOverflow
nop
nop
nop
nop
nop ; No Operation
nop
nop
nop
loc_402060:
sahf
sahf
sahf ; Store AH into Flags Register
sahf
The code is really long, and a little confusing.
I've commented almost every line so that it would be self-explanatory.
The Best way to see how this works would be to read this line by line as you are
single stepping the program from the Debugger.[/font:2oqg28s5] _________________ One thing only I know, and that is that I know nothing. (Socrates)
|
|
Back to top |
|
|
|
_aLfa_ Site Admin
Joined: 21 Sep 2002 Posts: 233 Location: Aveiro, Portugal
|
Posted: Sat Feb 16, 2008 10:15 am
Post subject: XI. CONCLUSION [END1]
|
|
[font=Courier New:3mo212jj]As you saw earlier, once you understand the disassembled code, it is not that
difficult to write a key generating algorithm that would generate a valid key
for the program given above.
So don't be under the impression that just because something has been written in
VB, it will be impossible to crack it.
It is difficult, but not impossible. But there are techniques that can be used
to make code analysis much more difficult in Visual BASIC, and these techniques
shall be discussed in the next update of this tutorial.
Hope you've like this tutorial as well. I've rushed through on this one, so I'm
expecting loads of errors to have crept in. Please bring them to my notice so I
can make changes in the next update.
I'll be back with the Next Update Soon.
Actually, this is the last of the updates.
From now on, I'll be writing sequels to my tutorials, so that information won't
be repeated everytime. Each part will continue where the previous one left off.
Think of it as a new chapter of a book.
It's for the same reason that I've skipped a few topics from this *update*.
It'll be more organized from the next part.
Enjoy.[/font:3mo212jj] _________________ One thing only I know, and that is that I know nothing. (Socrates)
|
|
Back to top |
|
|
|
|
|
|
You can post new topics in this forum You can reply to topics in this forum You can edit your posts in this forum You can delete your posts in this forum You can vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|