Sizes
1 byte 8 bits 2 hex digits max of 255 1 opcode
2 bytes == 1 word
4 bytes == 2 word(dword)
Registers hold 4 bytes/32bit. The 16bit and 8bit counterparts may not be addressed directly
OllyDBG can control the program, we can control olly. Controlling the program ourselves is too much work. Ollydbg is a debugger so we can create breakpoints and step ins
Test buttons
From left to right:
Folder: Open a new file
Reverse: Restart the program
X: Terminate program
Play: Run the program all the way until end
Pause: Only when during run, you can pause then do steps
Step into: enter functions
Step over: execute function call once
The following, I have no actual idea. These are all guesses
Trace into:
Trace over:
Step break: run until next breakpoint
Make breakpoint: doesnât really work tho
Calls
You can call in 5 ways. Pretty sure this also applies to jumps
-
Call label. Jumps to label
-
Call address. Call 40400000 will jump to 40400000
-
Call register. Call eax will jump to the value inside eax.
-
Call dword. Call dword ptr [eax+5] will go to the value at address eax+5. If eax was like 1, then it would go to address 6.
-
Call <jmp to API> executes an api function. Check the specific api for what it does.
The win32 api is usually stored in dll files. Win32 api allows for elevated permissions(lower ring level) actions. You must also give it arguments for every api call.
mov
Mov dest, src
There are some variations like movs, mov sx, movsb which alter the bitsize and esi or edi.
The confusing ones will be like:
Mov dword ptr ds:[402177], eax
This means we move the value in eax into memory address 402177
Comment section
This is incredibly helpful, especially when its manually written. It helps you make sense of the mnemonics in an even clearer setting. Each comment corresponds to the line beside it
Win32 API help
Depreciated. In our case, we cannot consult for help using windows help feature. Windows 8 was the last version in which this was supported. Error opening Help in Windows-based programs: âFeature not includedâ or âHelp not supportedâ - Microsoft Support
Used to be so good too. Told you what parameters for each function.
What we have in its place is a more difficult to navigate webpage with mostly the same information. There is a charm, yâknow, to old dos and xp graphics. A bit of ugly graphic design goes a long way to keeping the reader engaged. Anyhow, here it is: https://learn.microsoft.com/en-us/windows/win32/api/
Decimal from signed 2s complement
You might have seen this when doing a rapidtables calculation:
FFFFFFFF, the largest 32bit number is also -1???
What does the decimal from signed 2âs complement mean?
Well, what we know is that it allows for negative numbers. And it all depends on the first digit.
From 0-7, all numbers are positive
From 8-F, all numbers will be negative
This makes quite a bit of sense when you realize that in binary, 7 is 0111 and 8 is 1000. And so on for 8 and above to F, the leftmost digit remains 1. We get the sign from the leftmost digit. 0 for positive, 1 for negative
So, why isnt -1 the just 4294967295 but negative?
And not only that, but the higher the negative hex, the smaller the decimal is? F0000000 = -268435456 but FFFFFFFF = -1.
The reason is that, the logic changes once we reach 8 as the first digit.
https://www.youtube.com/watch?v=RbJV-g9Lob8
What the image above means is that if the number is negative(1 in the leftmost digit), then the decimal value is: Hex - largest value possible
For 32bit, this largest possible value is 16^8 = 4294967296. For FFFFFFFF in this example, FFFFFFFF = 4294967295. So, 4294967295 - 4294967296 = -1. Checks out right?
The logic for positive numbers doesnât really work out, but we already know how to get positive numbers anyways. Just regular hexadecimals.
So therefore, the largest negative number will be 80000000
Crack #1
We are set up with a program in ollydbg that is a gatekeeper to free software(dubious in content). It asks for a valid license.
Grr, how could you! Donât you know? Open source open doors!
Lets enact our revenge.
First skill - Flag manipulation
The first skill we learn is to look at where the error message is located in memory.
We are reading the comments here. Some condition is forcing a jump towards the event that says âBAD BOY DETECTED. NO LICENSE FIEND!â and then exit the program.
If we loop up, we find that this is occurring because of a comparison that changes the zero flag.
The jnz will save us, but unfortunately we donât fulfill the conditions if we run it regularly to reach the jnz.
This means that after the comparison of eax and -1, the zero flag is ticked. Why is eax = -1?
Looking above, we find our answer. CALL <JMP & KERNEL32, CREATEFILEA> changes eax to -1 after completion.
https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
ÂCreateFileA is a winapi command. Lena tells us that it specifically looks for a filename. The filename in this case, is âKeyfile.datâ
We can assume then, that because we dont have this file âKeyfile.datâ, eax is turned to -1, thus causing our bad boy termination
So lets do this. Lets change the zero flag to false(0), then we can get to the jnz address and continue like we are legitimate customers.
And hey, it worked! We are now at 0001109A.
But we havenât hit it home yet. Theres still one last struggle we must overcome.
And that is, read file. https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
It asks for data in memory addresses that would have been altered during the CreateFileA function, but we skipped that.
The sad thing here is that we still donât have âKeyfile.datâ!!!! So, are we fucked?
Wallow in misery, or retaliate against the proprietors. Remember, everything program flow is decided by flags and jumps.
Readfile will test eax. That weird ass test over here.
Test eax, eax. This will AND eax with itself. Literally changes nothing, BUT it does flick the zero flag IF and only IF eax was 0 before.
What occurs after? A jnz yalrealy know.
Hereâs the rundown of what ReadFile does:
Readfile was going to read 0x46 at memory address 402173. Because it didnât find it, eax is now 0.
So letâs see the jumps. The JNZ is what we want to get to, the JMP probably leads to a bad place.
Indeed it does. The JMP to 004010F7 goes to write the bad boy message.
So we flick the zero flag after the test, get to the JNZ we want and then what happens?
IT LEADS TO THE BADBOY MESSAGE STILL!!!!
FUCK IT WE LOOK AT STRINGS.
Second skill - Referenced strings and backtracking
Referenced strings tab is pivotal. We dont want to search through heaps and tons of memory jungle to find all the badboys. So weâd read from here to view all referenced strings.
So letâs go to the good boy message we found.
Right, we found it, but we also need to find what jumps to this memory location.
Click the memory address with the arrow. You can see where it jumped from, you could also just follow the red line beside the memory address upwards.
We⊠are very close to where we were before.
Ok, well atleast we know we are on the right track.
We need to get to the JMP to 00011205. To do that from where we are in the program now, we need to analyze each of the conditional jumps below us and their memory jump location. Find the closest one that will lead cohesively to 000110D8(our jmp to the goodboy)
So, it looks like the JE on memory address 000110C9 will bring us closest to the goodboy jump, so we know we need to fufill that condition. The road to get there will be as follows:
-
Fail the JL jump on memory location 000110BF
-
Complete the JE jump to 000110D3
-
Fail the JL jump on memory location 000110D6
-
Complete the goodboy jump
How do we pass the JL jumps? Well the JL jump requires the S flag(sign) to be ticked on(1). Because we subtract and check if we got negative which means itâs smaller. So whenever we are on the jump pad, we must make sure that the S flag is 0.
How do we fuffil the JE flag? Retard, do i even need to tell you this? JE = JZ = Zero flag == 1
Alright, once we have made it here just enjoy the ride. Press this button to continue
Third skill - Patching
Right, now if you did this manually, you would have to change each flag during each jump, and that is quite the headache. We canât always be there to guide olly so lets make a patch.
You know all the conditionals like JNE, JL and stuff? If we need those to jump, then why not change those to just JMP?
We can do this by double clicking the opcodes and writing whatever JMP instead
This process is called assembling. We are rewriting the assembly code.
Letâs rewrite all the conditionals that we need.
-
The jnz after createfile
-
The jnz after readfile
-
The je before the goodboy(actually not really cuz it automatically is the same)
Note: we could also just change a jump to jump directly to the goodboy memory location. This would save a lot of time, but it may miss crucial memory modifications along the way.
If we follow the cohesive way, you may also remember that there are jumps we want to avoid.
-
The jl after readfile
-
The jl after the je
To avoid these, just turn them into junk instructions. The easiest way is to change them to operand NOP. This just adds 0 to eax.
Also check the box that says Fill with NOPâs. This will NOP the stragglers left behind that depend on that operand changed
DONT RUN YET! BEFORE YOU RUN! SAVE THE PATCHES
-
Select your modifications
-
Copy to executable. Both options are the same
There we go, go ahead and run the exe and see the goodboy message. Good boy!