Code we don’t want to have in our C Code
All register Saving and stack initialization is not ported to our C Code, because the compiler will do it later for us in our function.
Loading the saved register is ignored too.
Examples from our Source Code from part 2.
// Initialize Stack frame .text:0000000000010630 stdu %sp, -0x50(%sp) // Saving Register .text:0000000000010634 std %r31, 0x48(%sp)
Detecting Saving Register
First of all, all saved register are loaded before the blr instructions again… Else saving is senseless.
Second as you see in our example r31 is pushed on the stack without modifing it at all.
How do we start?
Since we always return r3 we can start of returning a 64-bit unsigned value, which get more precisly while we reverse but for not this is enough.
unsigned long long reversingFunction()
{
// It always returns r3 it is from the spec of our CPU
return r3;
}
Finding count of parameters?
In our CPU parameters are saved in r3 – rN and mostly saved in other registers at the start of the function.
If we check our code we will see this.
// Initialize Stack frame .text:0000000000010630 stdu %sp, -0x50(%sp) // Saving Register .text:0000000000010634 std %r31, 0x48(%sp) // stackpointer is copied to r31 we have to know that for the future but it is nothing special .text:0000000000010638 mr %r31, %sp // First parameter is saved in r0 .text:000000000001063C mr %r0, %r3 // Second parameter is saved in r9 .text:0000000000010640 mr %r9, %r4 // Third parameter is saved in r11 .text:0000000000010644 mr %r11, %r5
So what we know for now looks like this
#define uint64_t unsigned long long
uint64_t reversingFunction(uint64_t firstParameter, uint64_t secondParameter, uint64_t thirdParameter)
{
r0 = firstParameter;
r9 = secondParameter;
r11 = thirdParameter;
// It always returns r3 it is from the spec of our CPU
return r3;
}
Guessing and sometimes it is wrong but mostly it is right (If not this is no stone)
I let the first part as it is and won’t repeat copying it here again. Since I try to not jump that much around in the code. It will be for now okay todo so the code here just comes after the top one.
.text:0000000000010648 stw %r0, 0x80(%r31) .text:000000000001064C stw %r9, 0x88(%r31) .text:0000000000010650 stw %r11, 0x90(%r31) .text:0000000000010654 lwz %r0, 0x90(%r31) .text:0000000000010658 stw %r0, 0x38(%r31) .text:000000000001065C lwz %r0, 0x80(%r31) .text:0000000000010660 stw %r0, 0x34(%r31) .text:0000000000010664 lwz %r0, 0x88(%r31) .text:0000000000010668 stw %r0, 0x30(%r31)
Actually they all use word size instead of double word size values. r0, r9 and r11 are used earlier to save the parameter. So we guess it is used unsigned int instead of long longs.
So we change our parameters to unsigned int und define local variables for the stack addresses used. Since they are not used to save register. They are local variables.
What we got is this.
#define uint64_t unsigned long long
#define uint32_t unsigned int
uint64_t reversingFunction(uint32_t firstParameter, uint32_t secondParameter, uint32_t thirdParameter)
{
uint32_t sp80, sp88, sp90, sp38, sp34, sp30;
r0 = firstParameter;
r9 = secondParameter;
r11 = thirdParameter;
//.text:0000000000010648 stw %r0, 0x80(%r31)
sp80 = r0;
//.text:000000000001064C stw %r9, 0x88(%r31)
sp88 = r9;
//.text:0000000000010650 stw %r11, 0x90(%r31)
sp90 = r11;
//.text:0000000000010654 lwz %r0, 0x90(%r31)
r0 = sp90;
//.text:0000000000010658 stw %r0, 0x38(%r31)
sp38 = r0;
//.text:000000000001065C lwz %r0, 0x80(%r31)
r0 = sp80;
//.text:0000000000010660 stw %r0, 0x34(%r31)
sp34 = r0;
//.text:0000000000010664 lwz %r0, 0x88(%r31)
r0 = sp88;
//.text:0000000000010668 stw %r0, 0x30(%r31)
sp30 = r0;
// It always returns r3 it is from the spec of our CPU
return r3;
}
The CPU can’t access memory and push it in another memory part directly it uses in our case r0 todo that. In C this is no problem. So we minimize the code.
To precisly it reads from stack saves in r0 and saves r0 to a new local variable (stack). This can be done in one line in C. I commented out the two lines that get one all the time.
#define uint64_t unsigned long long
#define uint32_t unsigned int
uint64_t reversingFunction(uint32_t firstParameter, uint32_t secondParameter, uint32_t thirdParameter)
{
uint32_t sp80, sp88, sp90, sp38, sp34, sp30;
r0 = firstParameter;
r9 = secondParameter;
r11 = thirdParameter;
sp80 = r0;
sp88 = r9;
sp90 = r11;
// r0 = sp90;
// sp38 = r0;
sp38 = sp90;
// r0 = sp80;
// sp34 = r0;
sp34 = sp80;
// r0 = sp88;
// sp30 = r0;
sp30 = sp88;
// It always returns r3 it is from the spec of our CPU
return r3;
}
So weg got now:
#define uint64_t unsigned long long
#define uint32_t unsigned int
uint64_t reversingFunction(uint32_t firstParameter, uint32_t secondParameter, uint32_t thirdParameter)
{
uint32_t sp80, sp88, sp90, sp38, sp34, sp30;
r0 = firstParameter;
r9 = secondParameter;
r11 = thirdParameter;
sp80 = r0;
sp88 = r9;
sp90 = r11;
sp38 = sp90;
sp34 = sp80;
sp30 = sp88;
// It always returns r3 it is from the spec of our CPU
return r3;
}
We can minify that again (not needed but okay).
#define uint64_t unsigned long long
#define uint32_t unsigned int
uint64_t reversingFunction(uint32_t firstParameter, uint32_t secondParameter, uint32_t thirdParameter)
{
uint32_t sp80, sp88, sp90, sp38, sp34, sp30;
r0 = firstParameter;
r9 = secondParameter;
r11 = thirdParameter;
sp34 = sp80 = r0;
sp30 = sp88 = r9;
sp38 = sp90 = r11;
// It always returns r3 it is from the spec of our CPU
return r3;
}
Since we are able to remove all register useage we do so.
#define uint64_t unsigned long long
#define uint32_t unsigned int
uint64_t reversingFunction(uint32_t firstParameter, uint32_t secondParameter, uint32_t thirdParameter)
{
uint32_t sp80, sp88, sp90, sp38, sp34, sp30;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
// It always returns r3 it is from the spec of our CPU
return r3;
}
Now we managed to use no register (except return, but we don’t use that). If you look at the code we have extracted all parameter and local variables so far.
I recommend if you see such minimization options do it instant and try to use at least register as possible
so the code gets readable.
Let’s go on!
.text:000000000001066C b loc_1079C
We convert simple in:
#define uint64_t unsigned long long
#define uint32_t unsigned int
uint64_t reversingFunction(uint32_t firstParameter, uint32_t secondParameter, uint32_t thirdParameter)
{
uint32_t sp80, sp88, sp90, sp38, sp34, sp30;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
// It always returns r3 it is from the spec of our CPU
return r3;
}
Now we investigate loc_1079C
.text:000000000001079C lwz %r0, 0x38(%r31) .text:00000000000107A0 cmpwi cr7, %r0, 0 .text:00000000000107A4 bgt cr7, loc_10670
Again it uses r0 just as local register because it can’t compare with a stack value directly we ignore that and use our sp38 variable. r31 is like sp it was assigned at the start we remember that and ignore that it is r31 and substitute it in our head with sp
.
#define uint64_t unsigned long long
#define uint32_t unsigned int
uint64_t reversingFunction(uint32_t firstParameter, uint32_t secondParameter, uint32_t thirdParameter)
{
uint32_t sp80, sp88, sp90, sp38, sp34, sp30;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
//.text:000000000001079C lwz %r0, 0x38(%r31)
//.text:00000000000107A0 cmpwi cr7, %r0, 0
//.text:00000000000107A4 bgt cr7, loc_10670
if(sp38 > 0)
{
loc_10670:
}
loc_107A8:
// It always returns r3 it is from the spec of our CPU
return r3;
}
The Path splits
Since we have to reverse one way first we just take the shorter one here and this will fix the mysteri about the return value
.
.text:00000000000107A8 lwz %r0, 0x90(%r31) .text:00000000000107AC extsw %r0, %r0 .text:00000000000107B0 mr %r3, %r0 .text:00000000000107B4 ld %r11, arg_0(%sp) .text:00000000000107B8 ld %r31, -8(%r11) .text:00000000000107BC mr %sp, %r11 .text:00000000000107C0 blr
Looks like this:
#define uint64_t unsigned long long
#define uint32_t unsigned int
uint64_t reversingFunction(uint32_t firstParameter, uint32_t secondParameter, uint32_t thirdParameter)
{
uint32_t sp80, sp88, sp90, sp38, sp34, sp30;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
if(sp38 > 0)
{
loc_10670:
}
loc_107A8:
// load sp90 in r0
//.text:00000000000107A8 lwz %r0, 0x90(%r31)
// this is a sign that r0 is a signed integer because it extense the signed value from 32 bit to the full 64 bit register so r0 is a signed 32 bit integer value
//.text:00000000000107AC extsw %r0, %r0
// Assign our return value. Since r0 is a signed int return value is a signed int.
// I would guess sp90 is a signed int now too so we change that
//.text:00000000000107B0 mr %r3, %r0
// Loading the old stack pointer in r11 we ignore that (we can IGNORE THAT, just remember that it was done).
//.text:00000000000107B4 ld %r11, arg_0(%sp)
// Loading the saved register. Let me explain this in detail (/// = Explain this in detail)
/// The top line were like this
/// newSP = oldSP - 0x50;
/// newSP + 0x48 = r31
/// The oldSP is loaded so it is like
/// oldSP = newSP + 0x50
/// oldSP - 0x08 = newSP + 0x48
/// oldSP - 0x08 = (oldSP - 0x50) + 0x48
/// They are equal so it definitly loads the old saved r31 back in r31
//.text:00000000000107B8 ld %r31, -8(%r11)
// Restoring old stack (we can IGNORE THAT)
//.text:00000000000107BC mr %sp, %r11
//.text:00000000000107C0 blr
return r3;
}
Okay we change the commented lines now we know sp90 is a signed int. I conclude all related to sp90 is signed too. SP90 get returned so a signed int as return and we know the return value…
Looks like this (we got quite far already):
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(uint32_t firstParameter, uint32_t secondParameter, int thirdParameter)
{
uint32_t sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
if(sp38 > 0)
{
loc_10670:
}
loc_107A8:
return sp90;
}
Okay now loc_10670:
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(uint32_t firstParameter, uint32_t secondParameter, int thirdParameter)
{
uint32_t sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
if(sp38 > 0)
{
loc_10670:
// An simple if on sp38 again
//.text:0000000000010670 lwz %r0, 0x38(%r31)
//.text:0000000000010674 cmpwi cr7, %r0, 7
//.text:0000000000010678 ble cr7, loc_106BC
if(sp38 <= 7)
{
loc_106BC:
}
loc_1067C:
}
loc_107A8:
return sp90;
}
I will choose the if routes now so we got a basic structure of the code already. I will go on all of them in one hit now. Too shorten things it’s always the same.
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(uint32_t firstParameter, uint32_t secondParameter, int thirdParameter)
{
uint32_t sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
if(sp38 > 0)
{
loc_10670:
if(sp38 <= 7)
{
loc_106BC:
// An simple if on sp38 again
//.text:00000000000106BC lwz %r0, 0x38(%r31)
//.text:00000000000106C0 cmpwi cr7, %r0, 3
//.text:00000000000106C4 ble cr7, loc_10708
if(sp38 <= 3)
{
loc_10708:
// An simple if on sp38 again
//.text:0000000000010708 lwz %r0, 0x38(%r31)
//.text:000000000001070C cmpwi cr7, %r0, 1
//.text:0000000000010710 ble cr7, loc_10754
if(sp38 <= 1)
{
loc_10754:
// An simple if on sp38 again
//.text:0000000000010754 lwz %r0, 0x38(%r31)
//.text:0000000000010758 cmpwi cr7, %r0, 0
//.text:000000000001075C ble cr7, loc_1079C
if(sp38 <= 0)
{
goto loc_1079C; // this time we don't assigne a Label because we already have that one reversed at the top
}
loc_10760:
}
loc_10714:
}
loc_106C8:
}
loc_1067C:
}
loc_107A8:
return sp90;
}
Okay let’s look what we got here:
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(uint32_t firstParameter, uint32_t secondParameter, int thirdParameter)
{
uint32_t sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
if(sp38 > 0)
{
loc_10670:
if(sp38 <= 7)
{
loc_106BC:
if(sp38 <= 3)
{
loc_10708:
if(sp38 <= 1)
{
loc_10754:
if(sp38 <= 0)
{
goto loc_1079C;
}
loc_10760:
}
loc_10714:
}
loc_106C8:
}
loc_1067C:
}
loc_107A8:
return sp90;
}
Block loc_1067C
I will convert one block first. I choosed the highest one in the IDA graph that was missing.
All other parts are nearly as the same of that block after explained this one in detail I go through the rest faster. I know it since I know the real code too. It’s one of mine anyway, but normaly you would all do one by one. I just want to shorten things but you will understand what I mean soon.
Let’s start with one code block.
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(uint32_t firstParameter, uint32_t secondParameter, int thirdParameter)
{
uint32_t sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
if(sp38 > 0)
{
loc_10670:
if(sp38 <= 7)
{
loc_106BC:
if(sp38 <= 3)
{
loc_10708:
if(sp38 <= 1)
{
loc_10754:
if(sp38 <= 0)
{
goto loc_1079C;
}
loc_10760:
}
loc_10714:
}
loc_106C8:
}
loc_1067C:
// Okay we save sp34 in r11 and sp30 in r0 lets mind that in our brain no need to write that down for now
//.text:000000000001067C lwz %r11, 0x34(%r31)
//.text:0000000000010680 lwz %r0, 0x30(%r31)
// Since we just saved an int no need to write nulls to the top part of sp30...
// Let me explain r0 is sp30 so this looks in c like this I don't write this down in real code just to explain
/// r9 = (r0 << 0) & 0x00000000FFFFFFFF;
/// so just saves the int value of r0 (sp30) in r9 we keep that in mind
// so sp30 is casted in an int not interesting as long as we don't know what is done with the integer value
//.text:0000000000010684 rldicl %r9, %r0, 0,32
// Okay we decided just the line above is a cast of sp30 as int saved in r9
// which is used as pointer to load a double word so it is in uint64_t pointer here
// Our CPU uses 32 bit addresses mostly so we ignore the int conversion here.
// we could write this
// r0 = *((uint64_t*)(int)sp30);
// but the int cast is done from compiler anyway so we ignore it
// Look what we got:
//.text:0000000000010688 ld %r0, 0(%r9)
r0 = *((uint64_t*)sp30);
// Same as above just with sp34 now
//.text:000000000001068C rldicl %r9, %r11, 0,32
// instead of load it writes the double word to the adress of r9 (sp34)
//.text:0000000000010690 std %r0, 0(%r9)
*((uint64_t*)sp34) = r0;
// load our pointer sp34 to r9
//.text:0000000000010694 lwz %r9, 0x34(%r31)
// increase the pointer by 8 and save the result in r0
//.text:0000000000010698 addi %r0, %r9, 8
// store the by 8 increased pointer back to sp34
//.text:000000000001069C stw %r0, 0x34(%r31)
// We do it like this for example
sp34 = ((uint64_t*)sp34) + 1;
// Same as above just with sp30
//.text:00000000000106A0 lwz %r9, 0x30(%r31)
//.text:00000000000106A4 addi %r0, %r9, 8
//.text:00000000000106A8 stw %r0, 0x30(%r31)
sp30 = ((uint64_t*)sp30) + 1;
// oh sp38 gets decreased by 8
// same as above with sp38 just -8 instead of +8
// we know already that this is not a pointer because never is data loaded from it
// you may have a clue now what this is
//.text:00000000000106AC lwz %r9, 0x38(%r31)
//.text:00000000000106B0 addi %r0, %r9, -8
//.text:00000000000106B4 stw %r0, 0x38(%r31)
sp38 -= 8;
// simple go back to the top
//.text:00000000000106B8 b loc_1079C
goto loc_1079C;
}
loc_107A8:
return sp90;
}
NOTE: Since we know now that sp34 is a pointer to some address we can assign (uint64_t*) to all sp34 and sp30 assoziated variables now
We got something like this now:
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(uint64_t* firstParameter, uint64_t* secondParameter, int thirdParameter)
{
uint64_t* sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
if(sp38 > 0)
{
loc_10670:
if(sp38 <= 7)
{
loc_106BC:
if(sp38 <= 3)
{
loc_10708:
if(sp38 <= 1)
{
loc_10754:
if(sp38 <= 0)
{
goto loc_1079C;
}
loc_10760:
}
loc_10714:
}
loc_106C8:
}
loc_1067C:
*((uint64_t*)sp34) = *((uint64_t*)sp30);
sp34 = ((uint64_t*)sp34) + 1;
sp30 = ((uint64_t*)sp30) + 1;
sp38 -= 8;
goto loc_1079C;
}
loc_107A8:
return sp90;
}
The other 3 Blocks
Now the other 3 parts we go fast through since they are nearly the same as the loc_1067C block. Normaly you would investigate in detail, but I shorten here.
#define uint64_t unsigned long long
#define uint32_t unsigned int
// I changed it to void* because you will see the other blocks use the pointers as other pointers than uint64_t*
int reversingFunction(void* firstParameter, void* secondParameter, int thirdParameter)
{
void* sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_10760:
// look at Block loc_1067C it's the same just byte is used instead of double word
//.text:0000000000010760 lwz %r11, 0x34(%r31)
//.text:0000000000010764 lwz %r0, 0x30(%r31)
//.text:0000000000010768 rldicl %r9, %r0, 0,32
//.text:000000000001076C lbz %r0, 0(%r9)
//.text:0000000000010770 rldicl %r9, %r11, 0,32
//.text:0000000000010774 stb %r0, 0(%r9)
*((char*)sp34) = *((char*)sp30);
// look at Block loc_1067C it's the same just byte is used instead of double word
//.text:0000000000010778 lwz %r9, 0x34(%r31)
//.text:000000000001077C addi %r0, %r9, 1
//.text:0000000000010780 stw %r0, 0x34(%r31)
sp34 = ((char*) sp34) + 1;
// look at Block loc_1067C it's the same just byte is used instead of double word
//.text:0000000000010784 lwz %r9, 0x30(%r31)
//.text:0000000000010788 addi %r0, %r9, 1
//.text:000000000001078C stw %r0, 0x30(%r31)
sp30 = ((char*) sp30) + 1;
// look at Block loc_1067C it's the same just byte is used instead of double word
//.text:0000000000010790 lwz %r9, 0x38(%r31)
//.text:0000000000010794 addi %r0, %r9, -1
//.text:0000000000010798 stw %r0, 0x38(%r31)
sp38 -= 1;
loc_1079C:
if(sp38 > 0)
{
loc_10670:
if(sp38 <= 7)
{
loc_106BC:
if(sp38 <= 3)
{
loc_10708:
if(sp38 <= 1)
{
loc_10754:
if(sp38 <= 0)
{
goto loc_1079C;
}
// IMPROTANT!!!: To stay at the code flow you see in text line this block is just above loc_1079C
// In graph view of IDA we couldn't see that but in text view the code will continue after the execution at
// loc_1079C
// How to solve this
// 1. create a Label above loc_1079C and jump to that label with
// like this
goto loc_10760;
}
loc_10714:
// look at Block loc_1067C it's the same just half word is used instead of double word
//.text:0000000000010714 lwz %r11, 0x34(%r31)
//.text:0000000000010718 lwz %r0, 0x30(%r31)
//.text:000000000001071C rldicl %r9, %r0, 0,32
//.text:0000000000010720 lhz %r0, 0(%r9)
//.text:0000000000010724 rldicl %r9, %r11, 0,32
//.text:0000000000010728 sth %r0, 0(%r9)
*((unsigned short*)sp34) = *((unsigned short*)sp30);
// look at Block loc_1067C it's the same just half word is used instead of double word
//.text:000000000001072C lwz %r9, 0x34(%r31)
//.text:0000000000010730 addi %r0, %r9, 2
//.text:0000000000010734 stw %r0, 0x34(%r31)
sp34 = ((unsigned short*)sp34) + 1;
// look at Block loc_1067C it's the same just half word is used instead of double word
//.text:0000000000010738 lwz %r9, 0x30(%r31)
//.text:000000000001073C addi %r0, %r9, 2
//.text:0000000000010740 stw %r0, 0x30(%r31)
sp30 = ((unsigned short*)sp30) + 1;
// look at Block loc_1067C it's the same just half word is used instead of double word
//.text:0000000000010744 lwz %r9, 0x38(%r31)
//.text:0000000000010748 addi %r0, %r9, -2
//.text:000000000001074C stw %r0, 0x38(%r31)
sp38 -= 2;
//.text:0000000000010750 b loc_1079C
goto loc_1079C;
}
loc_106C8:
// look at Block loc_1067C it's the same just word is used instead of double word
//.text:00000000000106C8 lwz %r11, 0x34(%r31)
//.text:00000000000106CC lwz %r0, 0x30(%r31)
//.text:00000000000106D0 rldicl %r9, %r0, 0,32
//.text:00000000000106D4 lwz %r0, 0(%r9)
//.text:00000000000106D8 rldicl %r9, %r11, 0,32
//.text:00000000000106DC stw %r0, 0(%r9)
// Explained in Block loc_1067C just this time word instead of double word
*((uint32_t*)sp34) = *((uint32_t*)sp30);
// look at Block loc_1067C it's the same just word is used instead of double word
//.text:00000000000106E0 lwz %r9, 0x34(%r31)
//.text:00000000000106E4 addi %r0, %r9, 4
//.text:00000000000106E8 stw %r0, 0x34(%r31)
sp34 = ((uint32_t*)sp34) + 1;
// look at Block loc_1067C it's the same just word is used instead of double word
//.text:00000000000106EC lwz %r9, 0x30(%r31)
//.text:00000000000106F0 addi %r0, %r9, 4
//.text:00000000000106F4 stw %r0, 0x30(%r31)
sp30 = ((uint32_t*)sp30) + 1;
// look at Block loc_1067C it's the same just word is used instead of double word
//.text:00000000000106F8 lwz %r9, 0x38(%r31)
//.text:00000000000106FC addi %r0, %r9, -4
//.text:0000000000010700 stw %r0, 0x38(%r31)
sp38 -= 4;
//.text:0000000000010704 b loc_1079C
goto loc_1079C;
}
loc_1067C:
*((uint64_t*)sp34) = *((uint64_t*)sp30);
sp34 = ((uint64_t*)sp34) + 1;
sp30 = ((uint64_t*)sp30) + 1;
sp38 -= 8;
goto loc_1079C;
}
loc_107A8:
return sp90;
}
Okay we are done and it looks like this:
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(void* firstParameter, void* secondParameter, int thirdParameter)
{
void* sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_10760:
*((char*)sp34) = *((char*)sp30);
sp34 = ((char*) sp34) + 1;
sp30 = ((char*) sp30) + 1;
sp38 -= 1;
loc_1079C:
if(sp38 > 0)
{
loc_10670:
if(sp38 <= 7)
{
loc_106BC:
if(sp38 <= 3)
{
loc_10708:
if(sp38 <= 1)
{
loc_10754:
if(sp38 <= 0)
{
goto loc_1079C;
}
goto loc_10760;
}
loc_10714:
*((unsigned short*)sp34) = *((unsigned short*)sp30);
sp34 = ((unsigned short*)sp34) + 1;
sp30 = ((unsigned short*)sp30) + 1;
sp38 -= 2;
goto loc_1079C;
}
loc_106C8:
*((uint32_t*)sp34) = *((uint32_t*)sp30);
sp34 = ((uint32_t*)sp34) + 1;
sp30 = ((uint32_t*)sp30) + 1;
sp38 -= 4;
goto loc_1079C;
}
loc_1067C:
*((uint64_t*)sp34) = *((uint64_t*)sp30);
sp34 = ((uint64_t*)sp34) + 1;
sp30 = ((uint64_t*)sp30) + 1;
sp38 -= 8;
goto loc_1079C;
}
loc_107A8:
return sp90;
}
Okay now two things we can do. Replace spXX with more speaking names by investigating what this code does, but I recommend to sort the code with the next part. Called Code Flow…
Code Flow
We are lucky since the code under every if (if the condition is false) always jumps somewhere different so we can inject else there for sure without damaging the code flow.
This will look like this:
NOTE: Only inject else clauses if you are sure it don’t disturbe the code flow.
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(void* firstParameter, void* secondParameter, int thirdParameter)
{
void* sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_10760:
*((char*)sp34) = *((char*)sp30);
sp34 = ((char*) sp34) + 1;
sp30 = ((char*) sp30) + 1;
sp38 -= 1;
loc_1079C:
if(sp38 > 0)
{
loc_10670:
if(sp38 <= 7)
{
loc_106BC:
if(sp38 <= 3)
{
loc_10708:
if(sp38 <= 1)
{
loc_10754:
if(sp38 <= 0)
{
goto loc_1079C;
}
else
{
goto loc_10760;
}
}
else
{
loc_10714:
*((unsigned short*)sp34) = *((unsigned short*)sp30);
sp34 = ((unsigned short*)sp34) + 1;
sp30 = ((unsigned short*)sp30) + 1;
sp38 -= 2;
goto loc_1079C;
}
}
else
{
loc_106C8:
*((uint32_t*)sp34) = *((uint32_t*)sp30);
sp34 = ((uint32_t*)sp34) + 1;
sp30 = ((uint32_t*)sp30) + 1;
sp38 -= 4;
goto loc_1079C;
}
}
else
{
loc_1067C:
*((uint64_t*)sp34) = *((uint64_t*)sp30);
sp34 = ((uint64_t*)sp34) + 1;
sp30 = ((uint64_t*)sp30) + 1;
sp38 -= 8;
goto loc_1079C;
}
}
loc_107A8:
return sp90;
}
Sometimes switching the blocks if code block with else code block AND inverting the condition check will make a more common structure.
I guess you will directly see when you see this code transformation now:
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(void* firstParameter, void* secondParameter, int thirdParameter)
{
void* sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_10760:
*((char*)sp34) = *((char*)sp30);
sp34 = ((char*) sp34) + 1;
sp30 = ((char*) sp30) + 1;
sp38 -= 1;
loc_1079C:
if(sp38 > 0)
{
loc_10670:
//if(sp38 <= 7)
if(sp38 > 7)
{
loc_1067C:
*((uint64_t*)sp34) = *((uint64_t*)sp30);
sp34 = ((uint64_t*)sp34) + 1;
sp30 = ((uint64_t*)sp30) + 1;
sp38 -= 8;
goto loc_1079C;
}
else
{
loc_106BC:
//if(sp38 <= 3)
if(sp38 > 3)
{
loc_106C8:
*((uint32_t*)sp34) = *((uint32_t*)sp30);
sp34 = ((uint32_t*)sp34) + 1;
sp30 = ((uint32_t*)sp30) + 1;
sp38 -= 4;
goto loc_1079C;
}
else
{
loc_10708:
//if(sp38 <= 1)
if(sp > 1)
{
loc_10714:
*((unsigned short*)sp34) = *((unsigned short*)sp30);
sp34 = ((unsigned short*)sp34) + 1;
sp30 = ((unsigned short*)sp30) + 1;
sp38 -= 2;
goto loc_1079C;
}
else
{
loc_10754:
if(sp38 > 0)
{
goto loc_10760;
}
else
{
goto loc_1079C;
}
}
}
}
}
loc_107A8:
return sp90;
}
Okay we remove all none called labels and restructure the else { if { } } structures to else ifs:
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(void* firstParameter, void* secondParameter, int thirdParameter)
{
void* sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
if(sp38 > 0)
{
if(sp38 > 7)
{
loc_1067C:
*((uint64_t*)sp34) = *((uint64_t*)sp30);
sp34 = ((uint64_t*)sp34) + 1;
sp30 = ((uint64_t*)sp30) + 1;
sp38 -= 8;
goto loc_1079C;
}
else if(sp38 > 3)
{
loc_106C8:
*((uint32_t*)sp34) = *((uint32_t*)sp30);
sp34 = ((uint32_t*)sp34) + 1;
sp30 = ((uint32_t*)sp30) + 1;
sp38 -= 4;
goto loc_1079C;
}
else if(sp > 1)
{
loc_10714:
*((unsigned short*)sp34) = *((unsigned short*)sp30);
sp34 = ((unsigned short*)sp34) + 1;
sp30 = ((unsigned short*)sp30) + 1;
sp38 -= 2;
goto loc_1079C;
}
else if(sp38 > 0)
{
// Since this is the only place the loc_10760 Code is called and executed we copy it here
// goto loc_10760;
loc_10760:
*((char*)sp34) = *((char*)sp30);
sp34 = ((char*) sp34) + 1;
sp30 = ((char*) sp30) + 1;
sp38 -= 1;
// AND we preserve the code flow with a goto to the code executed after loc_10760
goto loc_1079C;
}
else
{
goto loc_1079C;
}
}
return sp90;
}
Nearly finish…
We got this now looks quite nice already:
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(void* firstParameter, void* secondParameter, int thirdParameter)
{
void* sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
if(sp38 > 0)
{
if(sp38 > 7)
{
loc_1067C:
*((uint64_t*)sp34) = *((uint64_t*)sp30);
sp34 = ((uint64_t*)sp34) + 1;
sp30 = ((uint64_t*)sp30) + 1;
sp38 -= 8;
goto loc_1079C;
}
else if(sp38 > 3)
{
loc_106C8:
*((uint32_t*)sp34) = *((uint32_t*)sp30);
sp34 = ((uint32_t*)sp34) + 1;
sp30 = ((uint32_t*)sp30) + 1;
sp38 -= 4;
goto loc_1079C;
}
else if(sp > 1)
{
loc_10714:
*((unsigned short*)sp34) = *((unsigned short*)sp30);
sp34 = ((unsigned short*)sp34) + 1;
sp30 = ((unsigned short*)sp30) + 1;
sp38 -= 2;
goto loc_1079C;
}
else if(sp38 > 0)
{
loc_10760:
*((char*)sp34) = *((char*)sp30);
sp34 = ((char*) sp34) + 1;
sp30 = ((char*) sp30) + 1;
sp38 -= 1;
goto loc_1079C;
}
else
{
goto loc_1079C;
}
}
return sp90;
}
No matter what if or else if is executed all end with a jump to loc_1079C so we can just put it out of the ifs
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(void* firstParameter, void* secondParameter, int thirdParameter)
{
void* sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
goto loc_1079C;
loc_1079C:
if(sp38 > 0)
{
if(sp38 > 7)
{
loc_1067C:
*((uint64_t*)sp34) = *((uint64_t*)sp30);
sp34 = ((uint64_t*)sp34) + 1;
sp30 = ((uint64_t*)sp30) + 1;
sp38 -= 8;
}
else if(sp38 > 3)
{
loc_106C8:
*((uint32_t*)sp34) = *((uint32_t*)sp30);
sp34 = ((uint32_t*)sp34) + 1;
sp30 = ((uint32_t*)sp30) + 1;
sp38 -= 4;
}
else if(sp > 1)
{
loc_10714:
*((unsigned short*)sp34) = *((unsigned short*)sp30);
sp34 = ((unsigned short*)sp34) + 1;
sp30 = ((unsigned short*)sp30) + 1;
sp38 -= 2;
}
else if(sp38 > 0)
{
loc_10760:
*((char*)sp34) = *((char*)sp30);
sp34 = ((char*) sp34) + 1;
sp30 = ((char*) sp30) + 1;
sp38 -= 1;
}
goto loc_1079C;
}
return sp90;
}
While?
You have to know that, it’s hard to explain if you go into an if and the condition is true.
If that if body code jumps back to the if this is by definition a while clause.
Think about it makes totaly sense
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(void* firstParameter, void* secondParameter, int thirdParameter)
{
void* sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
// loc_1079C:
// if(sp38 > 0)
while(sp38 > 0)
{
if(sp38 > 7)
{
loc_1067C:
*((uint64_t*)sp34) = *((uint64_t*)sp30);
sp34 = ((uint64_t*)sp34) + 1;
sp30 = ((uint64_t*)sp30) + 1;
sp38 -= 8;
}
else if(sp38 > 3)
{
loc_106C8:
*((uint32_t*)sp34) = *((uint32_t*)sp30);
sp34 = ((uint32_t*)sp34) + 1;
sp30 = ((uint32_t*)sp30) + 1;
sp38 -= 4;
}
else if(sp > 1)
{
loc_10714:
*((unsigned short*)sp34) = *((unsigned short*)sp30);
sp34 = ((unsigned short*)sp34) + 1;
sp30 = ((unsigned short*)sp30) + 1;
sp38 -= 2;
}
else if(sp38 > 0)
{
loc_10760:
*((char*)sp34) = *((char*)sp30);
sp34 = ((char*) sp34) + 1;
sp30 = ((char*) sp30) + 1;
sp38 -= 1;
}
// goto loc_1079C;
}
return sp90;
}
Now we got this:
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(void* firstParameter, void* secondParameter, int thirdParameter)
{
void* sp80, sp88, sp34, sp30;
int sp90, sp38;
sp34 = sp80 = firstParameter;
sp30 = sp88 = secondParameter;
sp38 = sp90 = thirdParameter;
while(sp38 > 0)
{
if(sp38 > 7)
{
*((uint64_t*)sp34) = *((uint64_t*)sp30);
sp34 = ((uint64_t*)sp34) + 1;
sp30 = ((uint64_t*)sp30) + 1;
sp38 -= 8;
}
else if(sp38 > 3)
{
*((uint32_t*)sp34) = *((uint32_t*)sp30);
sp34 = ((uint32_t*)sp34) + 1;
sp30 = ((uint32_t*)sp30) + 1;
sp38 -= 4;
}
else if(sp > 1)
{
*((unsigned short*)sp34) = *((unsigned short*)sp30);
sp34 = ((unsigned short*)sp34) + 1;
sp30 = ((unsigned short*)sp30) + 1;
sp38 -= 2;
}
else if(sp38 > 0)
{
*((char*)sp34) = *((char*)sp30);
sp34 = ((char*) sp34) + 1;
sp30 = ((char*) sp30) + 1;
sp38 -= 1;
}
}
return sp90;
}
Rename Local Variables and Remove unused Local variables
First we remove unused variables. In our case sp88, sp80.
sp90 get assigned and returned but never modified so we can use the third Parameter for it.
#define uint64_t unsigned long long
#define uint32_t unsigned int
int reversingFunction(void* firstParameter, void* secondParameter, int thirdParameter)
{
void* sp34, sp30;
int sp90, sp38;
sp34 = firstParameter;
sp30 = secondParameter;
sp38 = thirdParameter;
while(sp38 > 0)
{
if(sp38 > 7)
{
*((uint64_t*)sp34) = *((uint64_t*)sp30);
sp34 = ((uint64_t*)sp34) + 1;
sp30 = ((uint64_t*)sp30) + 1;
sp38 -= 8;
}
else if(sp38 > 3)
{
*((uint32_t*)sp34) = *((uint32_t*)sp30);
sp34 = ((uint32_t*)sp34) + 1;
sp30 = ((uint32_t*)sp30) + 1;
sp38 -= 4;
}
else if(sp > 1)
{
*((unsigned short*)sp34) = *((unsigned short*)sp30);
sp34 = ((unsigned short*)sp34) + 1;
sp30 = ((unsigned short*)sp30) + 1;
sp38 -= 2;
}
else if(sp38 > 0)
{
*((char*)sp34) = *((char*)sp30);
sp34 = ((char*) sp34) + 1;
sp30 = ((char*) sp30) + 1;
sp38 -= 1;
}
}
return thirdParameter;
}
Renaming the variables and all other names too…
Now look like this:
#define uint64_t unsigned long long
#define uint32_t unsigned int
#define uint16_t unsigned short
#define uint8_t char
int memcpy(void* dst, void* src, int size)
{
int sizeToCopy = size;
void* dstCopy = dst;
void* srcCopy = src;
while(sizeToCopy > 0)
{
if(sizeToCopy >= 8)
{
*((uint64_t*)dstCopy) = *((uint64_t*)srcCopy);
dstCopy = ((uint64_t*)dstCopy)+1;
srcCopy = ((uint64_t*)srcCopy)+1;
sizeToCopy -= 8;
}
else if(sizeToCopy >= 4)
{
*((uint32_t*)dstCopy) = *((uint32_t*)srcCopy);
dstCopy = ((uint32_t*)dstCopy)+1;
srcCopy = ((uint32_t*)srcCopy)+1;
sizeToCopy -= 4;
}
else if(sizeToCopy >= 2)
{
*((unsigned short*)dstCopy) = *((unsigned short*)srcCopy);
dstCopy = ((uint16_t*)dstCopy)+1;
srcCopy = ((uint16_t*)srcCopy)+1;
sizeToCopy -= 2;
}
else if(sizeToCopy >= 1)
{
*((uint8_t*)dstCopy) = *((uint8_t*)srcCopy);
dstCopy = ((uint8_t*)dstCopy)+1;
srcCopy = ((uint8_t*)srcCopy)+1;
sizeToCopy -= 1;
}
}
return size;
}
Ask me on twitter for questions this is a tough one I know. (@KDSBest on twitter
)
Stay tuned,
KDSBest
Leave a Reply