re-for-50-plz-50 寒假逆向生涯(6/100)
re-for-50-plz-50
這題目屬實沒法看偽代碼(當然,可以下載插件進行一系列幫助),在這里呢,我直接讀mips的指令集,因為涉及到的指令挺簡單的
MIPS32指令集對照
全部指令
.text:00401398 var_18 = -0x18 .text:00401398 var_10 = -0x10 .text:00401398 var_8 = -8 .text:00401398 var_4 = -4 .text:00401398 arg_0 = 0 .text:00401398 arg_4 = 4 .text:00401398 .text:00401398 addiu $sp, -0x28 .text:0040139C sw $ra, 0x28+var_4($sp) .text:004013A0 sw $fp, 0x28+var_8($sp) .text:004013A4 move $fp, $sp .text:004013A8 li $gp, 0x4AC770 .text:004013B0 sw $gp, 0x28+var_18($sp) .text:004013B4 sw $a0, 0x28+arg_0($fp) .text:004013B8 sw $a1, 0x28+arg_4($fp) .text:004013BC sw $zero, 0x28+var_10($fp) .text:004013C0 j loc_401434 .text:004013C4 move $at, $at .text:004013C8 # --------------------------------------------------------------------------- .text:004013C8 .text:004013C8 loc_4013C8: # CODE XREF: main+A4j .text:004013C8 lui $v0, 0x4A .text:004013CC addiu $v1, $v0, (meow - 0x4A0000) # "cbtcqLUBChERV[[Nh@_X^D]X_YPV[CJ" .text:004013D0 lw $v0, 0x28+var_10($fp) .text:004013D4 addu $v0, $v1, $v0 .text:004013D8 lb $v1, 0($v0) .text:004013DC lw $v0, 0x28+arg_4($fp) .text:004013E0 addiu $v0, 4 .text:004013E4 lw $a0, 0($v0) .text:004013E8 lw $v0, 0x28+var_10($fp) .text:004013EC addu $v0, $a0, $v0 .text:004013F0 lb $v0, 0($v0) .text:004013F4 xori $v0, 0x37 .text:004013F8 sll $v0, 24 .text:004013FC sra $v0, 24 .text:00401400 beq $v1, $v0, loc_401428 .text:00401404 move $at, $at .text:00401408 lui $v0, 0x47 .text:0040140C addiu $a0, $v0, (aNooooooooooooo - 0x470000) # "NOOOOOOOOOOOOOOOOOO\n" .text:00401410 jal print .text:00401414 move $at, $at .text:00401418 lw $gp, 0x28+var_18($fp) .text:0040141C jal exit_funct .text:00401420 move $at, $at .text:00401424 lw $gp, 0x28+var_18($fp) .text:00401428 .text:00401428 loc_401428: # CODE XREF: main+68j .text:00401428 lw $v0, 0x28+var_10($fp) .text:0040142C addiu $v0, 1 .text:00401430 sw $v0, 0x28+var_10($fp) .text:00401434 .text:00401434 loc_401434: # CODE XREF: main+28j .text:00401434 lw $v0, 0x28+var_10($fp) .text:00401438 slti $v0, 0x1F .text:0040143C bnez $v0, loc_4013C8 .text:00401440 move $at, $at .text:00401444 lui $v0, 0x47 .text:00401448 addiu $a0, $v0, (aC0ngr4ssulatio - 0x470000) # "C0ngr4ssulations!! U did it." .text:0040144C la $v0, puts .text:00401450 move $t9, $v0 .text:00401454 jalr $t9 ; puts .text:00401458 move $at, $at .text:0040145C lw $gp, 0x28+var_18($fp) .text:00401460 jal exit_funct .text:00401464 move $at, $at .text:00401468 lw $gp, 0x28+var_18($fp) .text:0040146C li $v0, 1 .text:00401470 move $sp, $fp .text:00401474 lw $ra, 0x28+var_4($sp) .text:00401478 lw $fp, 0x28+var_8($sp) .text:0040147C addiu $sp, 0x28 .text:00401480 jr $ra .text:00401484 move $at, $at逐步分析
.text:00401398 addiu $sp, -0x28 .text:0040139C sw $ra, 0x28+var_4($sp) .text:004013A0 sw $fp, 0x28+var_8($sp) .text:004013A4 move $fp, $sp .text:004013A8 li $gp, 0x4AC770 .text:004013B0 sw $gp, 0x28+var_18($sp) .text:004013B4 sw $a0, 0x28+arg_0($fp) .text:004013B8 sw $a1, 0x28+arg_4($fp) .text:004013BC sw $zero, 0x28+var_10($fp)這幾行作用是代碼把棧頂抬升,然后進行一系列的存儲指令 對其賦值操作
接下來遇到無條件跳轉指令,
.text:004013C0 j loc_401434無條件跳轉
.text:00401434 lw $v0, 0x28+var_10($fp) .text:00401438 slti $v0, 0x1F .text:0040143C bnez $v0, loc_4013C8 .text:00401440 move $at, $at .text:00401444 lui $v0, 0x47 .text:00401448 addiu $a0, $v0, (aC0ngr4ssulatio - 0x470000) # "C0ngr4ssulations!! U did it." .text:0040144C la $v0, puts .text:00401450 move $t9, $v0 .text:00401454 jalr $t9 ; puts .text:00401458 move $at, $at .text:0040145C lw $gp, 0x28+var_18($fp) .text:00401460 jal exit_funct .text:00401464 move $at, $at .text:00401468 lw $gp, 0x28+var_18($fp) .text:0040146C li $v0, 1 .text:00401470 move $sp, $fp .text:00401474 lw $ra, 0x28+var_4($sp) .text:00401478 lw $fp, 0x28+var_8($sp) .text:0040147C addiu $sp, 0x28 .text:00401480 jr $ra .text:00401484 move $at, $at .text:00401434 lw $v0, 0x28+var_10($fp) .text:00401438 slti $v0, 0x1F
這兩行指令的話,取了一個數,0x28+var_10($fp)里面放的是0(上面用zero寄存器去初始化的內存單元),然后取出放在v0寄存器里面,這個數去和31比較,比較后的關系用1和0放在v0里面
解釋一下,v0<31的話,那么v0會被賦值為1,v0>=31的話,那么v0會被賦值為0
BENZ R1,NAME;//R1!=0,程序跳轉,以NAME為偏移地址
BEQZ R1,NAME;//R1=0,程序跳轉到,以NAME為偏移地址。
根據以上條件,然后0<31,成立,即跳轉到loc_4013C8
條件跳轉(主體代碼)
.text:004013C8 lui $v0, 0x4A .text:004013CC addiu $v1, $v0, (meow - 0x4A0000) # "cbtcqLUBChERV[[Nh@_X^D]X_YPV[CJ" .text:004013D0 lw $v0, 0x28+var_10($fp) .text:004013D4 addu $v0, $v1, $v0 .text:004013D8 lb $v1, 0($v0) .text:004013DC lw $v0, 0x28+arg_4($fp) .text:004013E0 addiu $v0, 4 .text:004013E4 lw $a0, 0($v0) .text:004013E8 lw $v0, 0x28+var_10($fp) .text:004013EC addu $v0, $a0, $v0 .text:004013F0 lb $v0, 0($v0) .text:004013F4 xori $v0, 0x37 .text:004013F8 sll $v0, 24 .text:004013FC sra $v0, 24 .text:00401400 beq $v1, $v0, loc_401428 .text:00401404 move $at, $at .text:00401408 lui $v0, 0x47 .text:0040140C addiu $a0, $v0, (aNooooooooooooo - 0x470000) # "NOOOOOOOOOOOOOOOOOO\n" .text:00401410 jal print .text:00401414 move $at, $at .text:00401418 lw $gp, 0x28+var_18($fp) .text:0040141C jal exit_funct .text:00401420 move $at, $at .text:00401424 lw $gp, 0x28+var_18($fp)逐步分析主體
第一步
.text:004013C8 lui $v0, 0x4A .text:004013CC addiu $v1, $v0, (meow - 0x4A0000) # "cbtcqLUBChERV[[Nh@_X^D]X_YPV[CJ"lui指令是load unsigned int 加載一個立即數進入v0寄存器的高16位
低16位填0,v0此時值為0x4A0000
第二行 addiu $v1, $v0, (meow - 0x4A0000) # 此時即可解釋為
v1=v0+meow - 0x4A0000
即v1=meow,meow此時應該是這個字符串的首地址,即把字符串首地址放入了
v1寄存器
從一個fp里面存放一個地址值,然后fp里面的地址值+0x28+var_10這個地址中的值讀取一個字到$v0,而且根據
所述,fp里面的地址值+0x28+var_10(處理相對于字符首地址的偏移,到后面就會發現,這個地方會依次+1)這個地址中的值是為0,即寄存器v0存儲是為0
第二步
接下來分析這里
.text:004013D4 addu $v0, $v1, $v0 .text:004013D8 lb $v1, 0($v0) .text:004013DC lw $v0, 0x28+arg_4($fp) .text:004013E0 addiu $v0, 4 .text:004013E4 lw $a0, 0($v0) .text:004013E8 lw $v0, 0x28+var_10($fp) .text:004013EC addu $v0, $a0, $v0 .text:004013F0 lb $v0, 0($v0) .text:004013F4 xori $v0, 0x37 .text:004013D4 addu $v0, $v1, $v0v0=v1+v0也就是v0=v1+0即v0=v1,也就是v0里面存放著字符串首地址
.text:004013D8 lb $v1, 0($v0)取出v0所指處的第一個字符串放在v1里面。
.text:004013DC lw $v0, 0x28+arg_4($fp)0x28+arg_4($fp)這個里面東西,
是從a1寄存器存進內存單元的,大概猜測是我們所輸進去的字符首地址(可是實際上不是)
這個加4的話,需要+4才能找到從我們傳進來的參數里面找到存儲字符串地址的內存單元
.text:004013E4 lw $a0, 0($v0)取出這個地址的一個字,這個字單元里面存儲了我們輸入字符串的首地址
.text:004013E8 lw $v0, 0x28+var_10($fp)把v0清零處理(處理相對于字符首地址的偏移,到后面就會發現,這個地方會依次+1)0x28+var_10($fp)這個里面存放的是$zero
.text:004013EC addu $v0, $a0, $v0這里是v0=v0+a0,即v0=a0,到這里我感覺才是我們輸入字符串的首地址
.text:004013F0 lb $v0, 0($v0)然后取出一個字節的字符出來放在v0里面
.text:004013F4 xori $v0, 0x37這個字符再和0x37進行異或操作
.text:004013F8 sll $v0, 24 .text:004013FC sra $v0, 24 .text:00401400 beq $v1, $v0, loc_401428 .text:00401404 move $at, $at .text:00401408 lui $v0, 0x47 .text:0040140C addiu $a0, $v0, (aNooooooooooooo - 0x470000) # "NOOOOOOOOOOOOOOOOOO\n" .text:00401410 jal print .text:00401414 move $at, $at .text:00401418 lw $gp, 0x28+var_18($fp) .text:0040141C jal exit_funct .text:00401420 move $at, $at .text:00401424 lw $gp, 0x28+var_18($fp)異或結束后,再
把它們左移24位,然后再右移24位,它倆的意思也就是取后八位的意思,就是取一個字節
相等的話,那就跳轉嘍,然后繼續判斷下一個字符
.text:00401428 loc_401428: .text:00401428 lw $v0, 0x28+var_10($fp) .text:0040142C addiu $v0, 1 .text:00401430 sw $v0, 0x28+var_10($fp)第一步用0x28+var_10($fp)把v0清0,然后進行+1操作,再把它存儲在0x28+var_10這個里面,
以此類推,下次到達這里也就是用1去覆蓋v0嘍,然后v0+1再去放在0x28+var_10這個里面,這個也就是那個字符串相對于首地址的偏移,以此來取出每個字符操作。
然后
text:00401434 loc_401434: # CODE XREF: main+28j .text:00401434 lw $v0, 0x28+var_10($fp) .text:00401438 slti $v0, 0x1F .text:0040143C bnez $v0, loc_4013C8這里呢,就把相對于字符的首地址的偏移和0x1F 比較,也就是能否成功比較到最后一個,如果能的話,那么就跳到成功的地方去了,因為比較每個字符是否相等的操作之間的跳轉已經在前面比較了,這里只需要比較是否到達最后即可。
GAMEOVER
#include <iostream> using namespace std; int main() {char a[] = { "cbtcqLUBChERV[[Nh@_X^D]X_YPV[CJ" };for (int i = 0; i < 31; i++) {a[i] = a[i] ^ 0x37;cout << a[i];} }注意點
存儲 從左往右
加載 從右往左
只需要注意著點,這個傳進來的參數0x28+arg_4($fp)存放的不是字符串的首地址,而是它存放的地址值+4之后才是存放輸入字符串地址的內存單元,即
0x28+arg_4($fp)取出里面的地址值+4 操作后,我們需要再往里面取一個word地址,即
然后a0里面存放的才是輸入字符串的首地址
總結
以上是生活随笔為你收集整理的re-for-50-plz-50 寒假逆向生涯(6/100)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: EasyRE 寒假逆向生涯(5/100
- 下一篇: MIPS32指令集