reversing.kr四道Easy题解题攻略
开篇废话
Nebula的level11做的有点头大,这时大神Jack又发来了逆向的题目,让我赶紧练练。虽然我负责比赛中逆向类的题目,但逆向题一般都比较难,先放出来的题基本都是其他类别,所以我就彻底成了打(跑)辅(龙)助(套)的角色~~~
这次这套题目来自reversing.kr,棒子的逆向挑战网站。话说棒子的Hacking能力还是挺强的,据说是个什么棒子的优选计划搞出来的成果。
本篇就记录一下4道名称是Easy开头题目,分别是Easy Crack、Easy Keygen、Easy Unpack和Easy ELF。这四题难度非常低,熟练地话掌握好节奏感可以蹭蹭蹭的秒题……
Easy Crack
程序启动后输入任意字符会显示一个MessageBox的Incorrect Password。打开OllyDbg,载入程序后查找到目标字符串Incorrect Password,之后转到程序,字符串前后代码如下:
00401080 /$ 83EC 64 sub esp,64
00401083 |. 57 push edi
00401084 |. B9 18000000 mov ecx,18
00401089 |. 33C0 xor eax,eax
0040108B |. 8D7C24 05 lea edi,dword ptr ss:[esp+5]
0040108F |. C64424 04 00 mov byte ptr ss:[esp+4],0
00401094 |. 6A 64 push 64 ; /Count = 64 (100.)
00401096 |. F3:AB rep stos dword ptr es:[edi] ; |
00401098 |. 66:AB stos word ptr es:[edi] ; |
0040109A |. AA stos byte ptr es:[edi] ; |
0040109B |. 8B7C24 70 mov edi,dword ptr ss:[esp+70] ; |
0040109F |. 8D4424 08 lea eax,dword ptr ss:[esp+8] ; |
004010A3 |. 50 push eax ; |Buffer
004010A4 |. 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)
004010A9 |. 57 push edi ; |hWnd
004010AA |. FF15 9C504000 call dword ptr ds:[<&USER32.GetDlgItemTe>; \GetDlgItemTextA
...
00401114 |. 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00401116 |. 68 58604000 push Easy_Cra.00406058 ; |EasyCrackMe
0040111B |. 68 44604000 push Easy_Cra.00406044 ; |Congratulation !!
00401120 |. 57 push edi ; |hOwner
00401121 |. FF15 A0504000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
00401127 |. 6A 00 push 0 ; /Result = 0
00401129 |. 57 push edi ; |hWnd
0040112A |. FF15 A4504000 call dword ptr ds:[<&USER32.EndDialog>] ; \EndDialog
00401130 |. 5F pop edi
00401131 |. 83C4 64 add esp,64
00401134 |. C3 retn
00401135 |> 6A 10 push 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00401137 |. 68 58604000 push Easy_Cra.00406058 ; |EasyCrackMe
0040113C |. 68 30604000 push Easy_Cra.00406030 ; |Incorrect Password
00401141 |. 57 push edi ; |hOwner
00401142 |. FF15 A0504000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
00401148 |. 5F pop edi
00401149 |. 83C4 64 add esp,64
0040114C \. C3 retn
程序通过GetDlgItemTextA获取输入字符串,之后经过一段算法判定对错。下面分析算法:
004010B0 |. 807C24 05 61 cmp byte ptr ss:[esp+5],61
004010B5 |. 75 7E jnz short Easy_Cra.00401135
首先确定esp+5位置字符为0x61,即a。
004010B7 |. 6A 02 push 2
004010B9 |. 8D4C24 0A lea ecx,dword ptr ss:[esp+A]
004010BD |. 68 78604000 push Easy_Cra.00406078 ; 5y
004010C2 |. 51 push ecx
004010C3 |. E8 88000000 call Easy_Cra.00401150 ; strcmp
004010C8 |. 83C4 0C add esp,0C
004010CB |. 85C0 test eax,eax
004010CD |. 75 66 jnz short Easy_Cra.00401135
之后判断esp+A处字符串是否为5y。 这里由于push 2
指令,栈针会上移4byte,因此此时esp=esp-4,所以现在的esp+A相当于上一次的esp-4+A(esp+6),这样就和上一次esp+5成为连续的字符串,也就是3个连续的字符为a5y。
004010CF |. 53 push ebx
004010D0 |. 56 push esi
004010D1 |. BE 6C604000 mov esi,Easy_Cra.0040606C ; R3versing
004010D6 |. 8D4424 10 lea eax,dword ptr ss:[esp+10]
004010DA |> 8A10 /mov dl,byte ptr ds:[eax]
004010DC |. 8A1E |mov bl,byte ptr ds:[esi]
004010DE |. 8ACA |mov cl,dl
004010E0 |. 3AD3 |cmp dl,bl
004010E2 |. 75 1E |jnz short Easy_Cra.00401102
004010E4 |. 84C9 |test cl,cl
004010E6 |. 74 16 |je short Easy_Cra.004010FE
004010E8 |. 8A50 01 |mov dl,byte ptr ds:[eax+1]
004010EB |. 8A5E 01 |mov bl,byte ptr ds:[esi+1]
004010EE |. 8ACA |mov cl,dl
004010F0 |. 3AD3 |cmp dl,bl
004010F2 |. 75 0E |jnz short Easy_Cra.00401102
004010F4 |. 83C0 02 |add eax,2
004010F7 |. 83C6 02 |add esi,2
004010FA |. 84C9 |test cl,cl
004010FC |.^ 75 DC \jnz short Easy_Cra.004010DA
004010FE |> 33C0 xor eax,eax
00401100 |. EB 05 jmp short Easy_Cra.00401107
00401102 |> 1BC0 sbb eax,eax
00401104 |. 83D8 FF sbb eax,-1
00401107 |> 5E pop esi
00401108 |. 5B pop ebx
00401109 |. 85C0 test eax,eax
0040110B |. 75 28 jnz short Easy_Cra.00401135
0040110D |. 807C24 04 45 cmp byte ptr ss:[esp+4],45
00401112 |. 75 21 jnz short Easy_Cra.00401135
之后匹配字符串R3versing,并在字符串头部(esp+4处)添加字符为E。因此答案为Ea5yR3versing。
这里算法由于涉及到esp的改变,因此OD跟踪起来比IDA静态分析更加简单。可以直接将程序跑起来,当程序碰到相关判断的地方(一般是cmp)会改变标志位(一般是ZF),只需要改变标志位寄存器的值让它按照你要的逻辑执行下去即可,当然你需要同时记录这些让逻辑保持正确的字符,你可以直接在栈(或数据区)中作出修改。之后当程序跑完之后,你的栈(或数据区)中就是一个正确的值。本程序栈的结构如下:
Easy Keygen
注册机题,readme要求Find the Name when the Serial is 5B134977135E7D13。程序跑起来,要求输入名字和序列号,测试了一下Name为abcde和随机的序列号,提示错误:
C:\Users\GreatYYX>"F:\Crack\reversingkr\Easy_KeygenMe\Easy Keygen.exe"
Input Name: abcde
Input Serial: 12345
Wrong
开OD跟着跑一下,下断点在InputName和InputSerial处,可以看到判定对错函数如下:
00401000 /$ 81EC 30010000 sub esp,130
00401006 |. 55 push ebp
00401007 |. 56 push esi
00401008 |. 57 push edi
00401009 |. B9 18000000 mov ecx,18
0040100E |. 33C0 xor eax,eax
00401010 |. 8D7C24 11 lea edi,dword ptr ss:[esp+11]
00401014 |. C64424 10 00 mov byte ptr ss:[esp+10],0
00401019 |. C64424 74 00 mov byte ptr ss:[esp+74],0
0040101E |. F3:AB rep stos dword ptr es:[edi]
00401020 |. 66:AB stos word ptr es:[edi]
00401022 |. AA stos byte ptr es:[edi]
00401023 |. B9 31000000 mov ecx,31
00401028 |. 33C0 xor eax,eax
0040102A |. 8D7C24 75 lea edi,dword ptr ss:[esp+75]
0040102E |. 68 60804000 push Easy_Key.00408060 ; Input Name:
00401033 |. F3:AB rep stos dword ptr es:[edi]
00401035 |. 66:AB stos word ptr es:[edi]
00401037 |. AA stos byte ptr es:[edi]
00401038 |. C64424 10 10 mov byte ptr ss:[esp+10],10 ; array, 3 bytes
0040103D |. C64424 11 20 mov byte ptr ss:[esp+11],20
00401042 |. C64424 12 30 mov byte ptr ss:[esp+12],30
00401047 |. E8 6D010000 call Easy_Key.004011B9
0040104C |. 83C4 04 add esp,4
0040104F |. 8D4424 10 lea eax,dword ptr ss:[esp+10]
00401053 |. 50 push eax
00401054 |. 68 5C804000 push Easy_Key.0040805C ; %s
00401059 |. E8 44010000 call Easy_Key.004011A2 ; input function
0040105E |. 8D7C24 18 lea edi,dword ptr ss:[esp+18]
00401062 |. 83C9 FF or ecx,FFFFFFFF
00401065 |. 33C0 xor eax,eax
00401067 |. 83C4 08 add esp,8
0040106A |. 33ED xor ebp,ebp
0040106C |. 33F6 xor esi,esi
0040106E |. F2:AE repne scas byte ptr es:[edi]
00401070 |. F7D1 not ecx
00401072 |. 49 dec ecx
00401073 |. 85C9 test ecx,ecx
00401075 |. 7E 3F jle short Easy_Key.004010B6
00401077 |> 83FE 03 /cmp esi,3
0040107A |. 7C 02 |jl short Easy_Key.0040107E
0040107C |. 33F6 |xor esi,esi
0040107E |> 0FBE4C34 0C |movsx ecx,byte ptr ss:[esp+esi+C]
00401083 |. 0FBE542C 10 |movsx edx,byte ptr ss:[esp+ebp+10]
00401088 |. 33CA |xor ecx,edx
0040108A |. 8D4424 74 |lea eax,dword ptr ss:[esp+74]
0040108E |. 51 |push ecx
0040108F |. 50 |push eax
00401090 |. 8D4C24 7C |lea ecx,dword ptr ss:[esp+7C]
00401094 |. 68 54804000 |push Easy_Key.00408054 ; %s%02X
00401099 |. 51 |push ecx
0040109A |. E8 B1000000 |call Easy_Key.00401150
0040109F |. 83C4 10 |add esp,10
004010A2 |. 45 |inc ebp
004010A3 |. 8D7C24 10 |lea edi,dword ptr ss:[esp+10]
004010A7 |. 83C9 FF |or ecx,FFFFFFFF
004010AA |. 33C0 |xor eax,eax
004010AC |. 46 |inc esi
004010AD |. F2:AE |repne scas byte ptr es:[edi]
004010AF |. F7D1 |not ecx
004010B1 |. 49 |dec ecx
004010B2 |. 3BE9 |cmp ebp,ecx
004010B4 |.^ 7C C1 \jl short Easy_Key.00401077
004010B6 |> B9 19000000 mov ecx,19
004010BB |. 33C0 xor eax,eax
004010BD |. 8D7C24 10 lea edi,dword ptr ss:[esp+10]
004010C1 |. 68 44804000 push Easy_Key.00408044 ; Input Serial:
004010C6 |. F3:AB rep stos dword ptr es:[edi]
...
0040111A |. 68 38804000 push Easy_Key.00408038 ; Correct!\n
0040111F |. E8 95000000 call Easy_Key.004011B9
00401124 |. 83C4 04 add esp,4
00401127 |. 33C0 xor eax,eax
00401129 |. 81C4 30010000 add esp,130
0040112F |. C3 retn
00401130 |> 68 30804000 push Easy_Key.00408030 ; Wrong\n
00401135 |. E8 7F000000 call Easy_Key.004011B9
0040113A |. 83C4 04 add esp,4
0040113D |. 33C0 xor eax,eax
0040113F |. 81C4 30010000 add esp,130
00401145 \. C3 retn
在00401059
即InputFunction处输入测试用的Name:abcde,并回车。之后程序跑到004010C1
即InputSerial处,查看栈数据:
0018FDEC 00000005
0018FDF0 0018FF88
0018FDF4 004011B5 Easy_Key.004011B5
0018FDF8 00000004
0018FDFC 0040109F Easy_Key.0040109F
0018FE00 0018FE84 ASCII "7142537445"
0018FE04 00408054 ASCII "%s%02X"
0018FE08 0018FE84 ASCII "7142537445"
0018FE0C 00000045
0018FE10 00000000
可以看到当Name为abcde的时候,栈在InputSerial前有数据ASCII "7142537445"
出现。通过InputSerial之后程序逻辑可以看出,这段字符串就是根据abcde算出的序列号,并用这个序列号和输入的序列号做对比。因此序列号算法在输入名字后、输入序列号之前(0040105E
-004010B4
)。
这段程序还原成C++代码后基本如下:
#include <iostream>
#include <string>
using namespace std;
void main(void)
{
char num[3] = {0x10, 0x20, 0x30};
char* name = "abcde";
int len = strlen(name) * 2 + 1;
char* serial = new char[len];
memset(serial, 0, len);
for(int i = 0, j = 0; j < strlen(name); i++, j++)
{
if(i >= 3)
i = 0;
sprintf(serial, "%s%02x", serial, *(name + j) ^ num[i]);
}
cout<<serial<<endl;
}
因此可以写出反函数:
#include <iostream>
#include <string>
using namespace std;
void main(void)
{
char num[3] = {0x10, 0x20, 0x30};
char* serial = "7142537445";
int len = strlen(serial) / 2 + 1;
char* name = new char[len];
memset(name, 0, len);
for(int i = 0, j = 0; j < strlen(serial); i++, j = j + 2)
{
if(i >= 3)
i = 0;
char serial_str[3];
serial_str[0] = *(serial + j);
serial_str[1] = *(serial + j + 1);
serial_str[2] = '\0';
sprintf(name, "%s%c", name, strtol(serial_str, NULL, 16) ^ num[i]);
}
cout<<name<<endl;
}
把serial用5B134977135E7D13带入跑出来Name为K3yg3nm3。
Easy Unpack
readme说需要找OEP,也就是不用脱壳,只需要找入口点。PEiD看一下,壳类型为ARVID's TDR file [Overlay] *
。才疏学浅,没看到过……不过既然是Easy Unpack,料着也不会难倒哪里去。
打开OD,载入程序,忽略各种错误。程序开始载入kernel32之后用了LoadLibrary、GetModuleHandle和FreeLibrary,典型的包装了IAT的壳。
0040A04B > 68 00A04000 push Easy_Unp.0040A000 ; ASCII "kernel32.dll"
0040A050 FF15 0DA04000 call dword ptr ds:[<&kernel32.LoadLibrar>; kernel32.LoadLibraryA
0040A056 A3 44A64000 mov dword ptr ds:[40A644],eax
0040A05B 68 18A64000 push Easy_Unp.0040A618 ; ASCII "GetModuleHandleA"
0040A060 50 push eax
0040A061 FF15 11A04000 call dword ptr ds:[<&kernel32.GetProcAdd>; apphelp.7054FFF6
0040A067 A3 48A64000 mov dword ptr ds:[40A648],eax
0040A06C 68 29A64000 push Easy_Unp.0040A629 ; ASCII "FreeLibrary"
0040A071 FF35 44A64000 push dword ptr ds:[40A644]
0040A077 FF15 11A04000 call dword ptr ds:[<&kernel32.GetProcAdd>; apphelp.7054FFF6
0040A07D A3 4CA64000 mov dword ptr ds:[40A64C],eax
之后是很长一段外壳操作,直到一个长jmp
:
0040A082 6A 00 push 0
0040A084 FF15 48A64000 call dword ptr ds:[40A648]
0040A08A A3 50A64000 mov dword ptr ds:[40A650],eax
0040A08F B9 00904000 mov ecx,Easy_Unp.00409000
0040A094 BA EE944000 mov edx,Easy_Unp.004094EE
0040A099 3BCA cmp ecx,edx
0040A09B 74 26 je short Easy_Unp.0040A0C3
0040A09D 8031 10 xor byte ptr ds:[ecx],10
0040A0A0 41 inc ecx
0040A0A1 3BCA cmp ecx,edx
0040A0A3 74 1E je short Easy_Unp.0040A0C3
...
0040A1ED 8031 40 xor byte ptr ds:[ecx],40
0040A1F0 41 inc ecx
0040A1F1 3BCA cmp ecx,edx
0040A1F3 74 06 je short Easy_Unp.0040A1FB
0040A1F5 8031 50 xor byte ptr ds:[ecx],50
0040A1F8 41 inc ecx
0040A1F9 ^ EB D6 jmp short Easy_Unp.0040A1D1
0040A1FB - E9 506FFFFF jmp Easy_Unp.00401150
程序单步到0040A1FB之后,长跳到00401150,发现二进制数据是55,条件反射push ebp
,函数入口,于是Ctrl+A强制汇编数据,熟悉的入口结构来了~~
00401150 /. 55 push ebp
00401151 |. 8BEC mov ebp,esp
00401153 |. 6A FF push -1
00401155 |. 68 D0504000 push Easy_Unp.004050D0
0040115A |. 68 1C1E4000 push Easy_Unp.00401E1C ; Entry address; SE 处理程序安装
0040115F |. 64:A1 0000000>mov eax,dword ptr fs:[0]
00401165 |. 50 push eax
00401166 |. 64:8925 00000>mov dword ptr fs:[0],esp
0040116D |. 83EC 58 sub esp,58
...
004011BC |> 8975 FC mov [local.1],esi
004011BF |. E8 E1070000 call Easy_Unp.004019A5
004011C4 |. FF15 38504000 call dword ptr ds:[405038] ; [GetCommandLineA
...
004011EE |. 50 push eax ; /pStartupinfo
004011EF |. FF15 34504000 call dword ptr ds:[405034] ; \GetStartupInfoA
004011F5 |. E8 1B030000 call Easy_Unp.00401515
...
0040120C |> 50 push eax
0040120D |. FF75 9C push [local.25]
00401210 |. 56 push esi
00401211 |. 56 push esi ; /pModule
00401212 |. FF15 30504000 call dword ptr ds:[405030] ; \GetModuleHandleA
因此OEP为00401150。确实非常简单~~
Easy ELF
三道Windows之后来了一道Linux,不过无所谓啦。拖到Linux里面,看一下文件类型。
root@YYX-Kali:~/upload# file Easy_ELF
Easy_ELF: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, BuildID[sha1]=0x409edb8e3182380a2f58d49c7323dd895c74e1b7, stripped
基本信息就是ELF32位可执行文件,链接动态库,去符号表。
运行一下程序,随便输入一点,提示Wrong
后直接退出。反复试了一些数字、字母之类的组合,都是一个结果。
打开IDA(Windows下),拖入,开始逆向分析。直接Shift+F12
打开字符串窗口找到找到Wrong
,之后利用交叉引用跳回到调用函数,稍微向上翻一点就能看到关键函数了:
.text:080484F7 ; =============== S U B R O U T I N E =======================================
.text:080484F7
.text:080484F7 ; Attributes: bp-based frame
.text:080484F7
.text:080484F7 sub_80484F7 proc near ; CODE XREF: sub_804851B+34p
.text:080484F7 push ebp
.text:080484F8 mov ebp, esp
.text:080484FA sub esp, 18h
.text:080484FD mov dword ptr [esp+8], 9 ; n
.text:08048505 mov dword ptr [esp+4], offset aCorrect ; "Correct!\n"
.text:0804850D mov dword ptr [esp], 1 ; fd
.text:08048514 call _write
.text:08048519 leave
.text:0804851A retn
.text:0804851A sub_80484F7 endp
.text:0804851A
.text:0804851B
.text:0804851B ; =============== S U B R O U T I N E =======================================
.text:0804851B
.text:0804851B ; Attributes: bp-based frame
.text:0804851B
.text:0804851B sub_804851B proc near ; DATA XREF: start+17o
.text:0804851B push ebp
.text:0804851C mov ebp, esp
.text:0804851E and esp, 0FFFFFFF0h
.text:08048521 sub esp, 10h
.text:08048524 mov dword ptr [esp+8], 17h ; n
.text:0804852C mov dword ptr [esp+4], offset aReversing_krEa ; "Reversing.Kr Easy ELF\n\n"
.text:08048534 mov dword ptr [esp], 1 ; fd
.text:0804853B call _write
.text:08048540 call sub_8048434 ; scanf
.text:08048545 call sub_8048451 ; main algorithm
.text:0804854A cmp eax, 1
.text:0804854D jnz short loc_804855B
.text:0804854F call sub_80484F7 ; correct
.text:08048554 mov eax, 0
.text:08048559 jmp short locret_804857C
.text:0804855B ; ---------------------------------------------------------------------------
.text:0804855B
.text:0804855B loc_804855B: ; CODE XREF: sub_804851B+32j
.text:0804855B mov dword ptr [esp+8], 6 ; n
.text:08048563 mov dword ptr [esp+4], offset aWrong ; "Wrong\n"
.text:0804856B mov dword ptr [esp], 1 ; fd
.text:08048572 call _write
.text:08048577 mov eax, 0
.text:0804857C
.text:0804857C locret_804857C: ; CODE XREF: sub_804851B+3Ej
.text:0804857C leave
.text:0804857D retn
.text:0804857D sub_804851B endp
.text:0804857D
.text:0804857D ; ---------------------------------------------------------------------------
sub_804851B函数是提示正确与错误的分支函数,其中四个call,write识别出来了,其他函数跟进去看一下(我已经注释),发现是scanf、主算法函数和返回Correct字符串的函数,其中当主算法函数返回1时判为正确。
然后就重点来看sub_8048451。转到图形视图,一组连续判断,只要逻辑沿着右边下来即可走通(最后eax为1,符合上面的判对条件)。
之后大致扫描了一下程序体,发现反复调用ds段寄存器指向的段内的一些byte,点进去看一下数据区布局(在.bss段,全局变量)。
.bss:0804A020 byte_804A020 db ? ; DATA XREF: sub_8048434+Bo
.bss:0804A020 ; sub_8048451:loc_8048469r ...
.bss:0804A021 byte_804A021 db ? ; DATA XREF: sub_8048451+3r
.bss:0804A022 byte_804A022 db ? ; DATA XREF: sub_8048451+27r
.bss:0804A022 ; sub_8048451+31w ...
.bss:0804A023 byte_804A023 db ? ; DATA XREF: sub_8048451+36r
.bss:0804A023 ; sub_8048451+40w ...
.bss:0804A024 byte_804A024 db ? ; DATA XREF: sub_8048451+45r
.bss:0804A025 byte_804A025 db ? ; DATA XREF: sub_8048451:loc_80484A8r
这段都是被引用数据,且是连续的,各1byte,你可以把它们格式化成数组,我比较懒,就不做这步了。基本可以确认数据区为连续的6个byte,即[20][21][22][23][24][25]。
下面进行主算法具体逻辑分析:
.text:08048451 sub_8048451 proc near ; CODE XREF: sub_804851B+2Ap
.text:08048451 push ebp
.text:08048452 mov ebp, esp
.text:08048454 movzx eax, ds:byte_804A021
.text:0804845B cmp al, 31h
.text:0804845D jz short loc_8048469
.text:0804845F mov eax, 0
.text:08048464 jmp loc_80484F5
第一段确定[21]等于0x31,就是'1'。
.text:08048469 loc_8048469: ; CODE XREF: sub_8048451+Cj
.text:08048469 movzx eax, ds:byte_804A020
.text:08048470 xor eax, 34h
.text:08048473 mov ds:byte_804A020, al
.text:08048478 movzx eax, ds:byte_804A022
.text:0804847F xor eax, 32h
.text:08048482 mov ds:byte_804A022, al
.text:08048487 movzx eax, ds:byte_804A023
.text:0804848E xor eax, 0FFFFFF88h
.text:08048491 mov ds:byte_804A023, al
.text:08048496 movzx eax, ds:byte_804A024
.text:0804849D cmp al, 58h
.text:0804849F jz short loc_80484A8
.text:080484A1 mov eax, 0
.text:080484A6 jmp short loc_80484F5
第二段做了连续异或,[20] xor 0x34, [22] xor 0x32, [23] xor 0x88, 之后判断[23]是不是为0x58,所以[23]为'X'。
.text:080484A8 loc_80484A8: ; CODE XREF: sub_8048451+4Ej
.text:080484A8 movzx eax, ds:byte_804A025
.text:080484AF test al, al
.text:080484B1 jz short loc_80484BA
.text:080484B3 mov eax, 0
.text:080484B8 jmp short loc_80484F5
第三段要求[25]为0,就是'\0',字符串结尾。
.text:080484BA
.text:080484BA loc_80484BA: ; CODE XREF: sub_8048451+60j
.text:080484BA movzx eax, ds:byte_804A022
.text:080484C1 cmp al, 7Ch
.text:080484C3 jz short loc_80484CC
.text:080484C5 mov eax, 0
.text:080484CA jmp short loc_80484F5
.text:080484CC ; ---------------------------------------------------------------------------
.text:080484CC
.text:080484CC loc_80484CC: ; CODE XREF: sub_8048451+72j
.text:080484CC movzx eax, ds:byte_804A020
.text:080484D3 cmp al, 78h
.text:080484D5 jz short loc_80484DE
.text:080484D7 mov eax, 0
.text:080484DC jmp short loc_80484F5
.text:080484DE ; ---------------------------------------------------------------------------
.text:080484DE
.text:080484DE loc_80484DE: ; CODE XREF: sub_8048451+84j
.text:080484DE movzx eax, ds:byte_804A023
.text:080484E5 cmp al, 0DDh
.text:080484E7 jz short loc_80484F0
.text:080484E9 mov eax, 0
.text:080484EE jmp short loc_80484F5
之后连续三段对刚才异或后的数字进行操作。异或的反函数还是异或,所以直接异或就能得到结果。这里用python计算一下:
>>> chr(0x32 ^ 0x7c)
'N'
>>> chr(0x34 ^ 0x78)
'L'
>>> chr(0x88 ^ 0xdd)
'U'`
所以[20]=L,[22]=N,[23]=U。
最后eax置1并返回。这样可以得到答案为L1NUX
。