Hello and welcome back.
In the previous lesson, we saw that we can use a method to bypass the UPX Packer by allowing the packed
program to first run and then launch our Python script to patch the memory
while it is running. Now, in this second, uh,
uh, like in this lesson,
now we are going to try something different.
This time we will use a Python program to run the program itself and then automatically patch the memory.
So it's slightly different.
So this type of program is called a loader.
The loader will launch the program for you and then search for the area where you want to patch, and
then apply the patch.
So for this video lesson, I have chosen my own Crackme, Crackme 11, which you can actually find from here,
or you can download from the resource section for this lecture.
So this was written originally to unpack and to create a loader.
But for this lesson we are just going to create a loader because I want to show you how Python can actually
be used for that purpose.
Now the first step before we can use the loader is we have to identify the area where we want to
patch.
So we have to analyze it first using x64dbg.
Before that, we run the program and we see it asks for a serial key.
If we enter any serial key, you click on the button "Check" and it gives a message "Sorry, wrong key."
So let's just click OK to dismiss it.
Now this program, if you scan it with DIE,
you will find that it is a 32-bit program,
PE32, and it is also packed with UPX Packer.
So
now let's, uh, open it with, uh, x32dbg.
And run the program.
Instead of doing a string search, we are going to try something different.
We are going to use the call stack method.
So the call stack is a place where it lists all the functions that have been called since the program
started.
The earliest program, the earliest call, is listed at the bottom.
The most recent calls are at the top, so that's why it's called a call stack.
So let's run it now.
So now, since it's running, the program has unpacked itself into memory.
So we can enter any wrong serial key.
Click "Check."
It says "Wrong key."
OK.
Now we pause the program.
Pause the debugger by clicking the pause button.
Click on this button and you see the state is now paused.
Now we go to the call stack.
We look for the user module,
the last user, user, user function
that was called.
These are all system calls.
From here onwards, you will see user, user.
User.
Another characteristic is you can look at the address.
If it's a high address like this, seven, seven, and so on, that means it's a system,
system call.
If it's a low address like, for, like this, then you know it's a user module.
Also you can confirm from memory map.
You can see the user module is here at this address range, starting with 004 onwards.
So let's go back.
Now
you can see, look for the 004 here.
This one is a good candidate.
So,
so this is a list of all the functions that have been called up to now.
So in order to know which function showed the bad message, the bad message, I remind you, is this one.
Which function is responsible for showing this?
We will trace the call stack.
So since this function is, since this, uh, bad message is the latest event, that means the latest
call will be at the top.
The latest calls which are responsible for that event will be at the top.
That's why we are looking, searching from top down rather than bottom up.
So we find that 004 is a good candidate to look into.
So this is under the column "To."
So we right-click on this.
Sometimes it can be under column "From," depends.
For example, if you're tracing, this will be under column "From."
But we want the most recent call,
so we trace this one first.
If it's wrong, we can always go down and down and down.
So now we look at this, right-click "Follow To," because this is under the column "To."
So we select "Follow To."
If it was under column "From," we select "Follow From."
So now you see, this is the place that call was made.
This call.
So we look up, you can see that there is a,
the string
"Sorry,
wrong key."
This is a text and this is the caption for the text box.
This is the text and the caption.
And so you have two, two, two types of messages which can be shown,
and here is the JE, "Jump Equal."
So if you put a breakpoint here,
right,
you can just double-click here to breakpoint.
And if you now
go back to our program, click OK.
OK, we have to run the debugger because we paused it just now, so just run the debugger.
And now we go back to our program.
OK.
And now we click "Check" again.
It will hit our breakpoint.
And from the breakpoint you will see that the grayed-out line shows that it is not going to jump.
It's also confirmed here.
Jump is not taken.
So it is going to go straight.
So we can trace it.
Trace coverage with "Step Over."
You see it's going straight.
It's loading the bad message.
And then this is a call that will show the bad message.
We step over it and then the bad message is shown.
"Sorry,
wrong key."
OK?
OK.
So now we know that if we want, if that were the correct message, or we have to reverse the JE jump
label.
So let's try that again.
Now we run.
To check.
It hits our breakpoint.
This time we want to reverse this jump, so we need to patch this.
Yes, the original opcode is 74 22.
We're going to patch it with JMP.
So before we patch it, we just copy this,
all these bytes here.
Binary copy and open Notepad and paste it into Notepad.
So this is the array of bytes that we want to
you want to search for.
Now, the longer the bytes, the more unique it will be.
If you are afraid that this pattern will be found in other parts of this module, then just increase
the bytes that you want to search for.
For example, like this, binary copy.
It's up to you.
You can search for a longer pattern like this.
Then it will be more unique.
So the longer it is, the more unique it gets.
We want it quite unique so that there will not be two locations in the executable that have the end, in an...
Otherwise you'll be patching twice.
I have done this before, and I found that this one is good enough, so we don't need to go for such
a long array of bytes.
So we use this.
So we want to patch this one to become a jump,
unconditional jump.
That means we want it to jump here.
So we assemble a, assemble an assembler instruction here.
Press spacebar.
And then we assemble a JMP.
Now make sure this is checked.
And you see instruction is same size.
So when you click OK,
close this,
you see that only one byte needs to be changed.
-.
You compare it here, that means you only need to change this byte to become -.
The rest remains unchanged.
So this is the array of bytes and then go down.
This is -.
So we are identifying the array of bytes that we are going to scan for and the bytes that we want to
replace,
to replace this.
So we'll just pause here and I'll come back and see you in the next lesson.
Don't close everything.
We'll see you in the next lesson.
Thank you for watching.