-
-
[原创]看雪 2017 CTF 第一题 JzJnzJmp
-
发表于: 2017-6-1 22:33 2826
-
主要消除反编译干扰,在边界与有限集合中求二元一次方程的解。
0x01
随机输出key,按注册"Register"得到错误提示"error !"
0x02
上IDA,查看字符信息SubView|String,溯源"error !"字符交叉索引点,定位注册业务逻辑
(1)"SubView|String"
.data:00408040 00000008 C error !
(2)溯源"error !"字符
.data:00408030 WindowName db 'PEDIY CTF 2017',0 ; DATA XREF: WinMain(x,x,x,x)
.data:00408040 Text db 'error !',0 ; DATA XREF: sub_4011F4:
.data:00408048 Caption db 'CrackMe 2017 CTF v2',0 ; DATA XREF: sub_4011F4
.data:0040805C aRegistrationSu db 'Registration successful !',0 ; DATA XREF:
.data:00408078 aCrackme2017Ctf db 'CrackMe 2017 CTF',0 ; DATA XREF: sub_4011F4
(3)"error !"字符交叉引用定位注册代码逻辑
.text:004012BC push 0
.text:004012BE push offset aCrackme2017Ctf ; "CrackMe 2017 CTF"
.text:004012C3 fnstsw ax
.text:004012C5 sahf
.text:004012C6 jnz short loc_4012D6
.text:004012C8 push offset aRegistrationSu ; "Registration successful !"
.text:004012CD jmp short loc_4012DB
.text:004012CF loc_4012CF:
.text:004012CF push 0 ; uType
.text:004012D1 push offset Caption ; "CrackMe 2017 CTF v2"
.text:004012D6 loc_4012D6: ;
.text:004012D6 push offset Text ; "error !"
.text:004012DB loc_4012DB: ;
.text:004012DB push hWnd ; hWnd
.text:004012E1 call ds:MessageBoxA
.text:004012E7 leave
.text:004012E8 retn
0x03
清除反编译干扰代码重建判断逻辑业务函数
反汇编干扰的模式只用一种(两处)jz RealAddr\jnz RealAddr\call(0xE8) xxx\RealAddr的方式
两处干扰分别从(1.1)\(2.1)变为(1.2)\(2.2)实际控制流,通过(3)(4)(5)(6)清除干扰重建函数体逻辑
(1.1)
.text:0040125E jz short near ptr loc_401262+1
.text:00401260 jnz short near ptr loc_401262+1
.text:00401262 loc_401262:
.text:00401262 call near ptr unk_48CACD
(1.2)
.text:0040125E jz short loc_401263
.text:00401260 jnz short loc_401263
.text:00401262 db 0E8h ;
.text:00401263 loc_401263:
.text:00401263 mov ax, 8
.text:00401267 xor ax, 7
(2.1)
.text:004012A6 jz short near ptr loc_4012AA+1
.text:004012A8 jnz short near ptr loc_4012AA+1
.text:004012AA loc_4012AA:
.text:004012AA call near ptr unk_48CB15
(2.2)
.text:004012A6 jz short loc_4012AB
.text:004012A8 jnz short loc_4012AB
.text:004012AA db 0E8h ;
.text:004012AB loc_4012AB:
.text:004012AB mov ax, 8
.text:004012AF xor ax, 7
(3)IDAPython清除[0x40125E,0x401263)区间反编译干扰冗余代码
for ea in (0x40125E,0x401263):
PatchByte(ea,0x90)
(4)同理清除[0x4012A6,0x4012AB)区间反编译干扰冗余代码
(5)在代码块[0x40125E,0x401263)与[0x4012A6,0x4012AB)起始地址
0x40125E和0x4012A6处快捷键"C"重建"nop"(0x90)指令
(6)在函数首地址0x4011F4处右键”Create Function“重建函数得到Hi_CheckKey_sub_4011F4
0x05
key校验函数Hi_CheckKey_sub_4011F4逻辑
(1)
.text:004011F4 push ebp
.text:004011F5 mov ebp, esp
.text:004011F7 sub esp, 1Ch
.text:004011FA lea eax, [ebp+loc_key]
.text:004011FD push 15h ; cchMax
.text:004011FF push eax ; lpString
.text:00401200 push 3E9h ; nIDDlgItem
.text:00401205 push Hi_hDlg ; hDlg
.text:0040120B call ds:GetDlgItemTextA
.text:00401211 push 1F4h ; dwMilliseconds
.text:00401216 call ds:Sleep
.text:0040121C lea eax, [ebp+loc_key]
.text:0040121F push eax ; char *
.text:00401220 call _strlen
.text:00401225 cmp eax, 4
.text:00401228 pop ecx
.text:00401229 jnz loc_4012CF
其中Hi_hDlg由下述交叉引用的赋值点上下文可知为注册对话框句柄
00401179 mov Hi_hDlg, eax
上述代码获取KeyEdit框的注册key存放于char loc_key[0x15]中,其中key长度限定为4
(2)
.text:00401229 jnz loc_4012CF
.text:0040122F push 30h
.text:00401231 pop ecx
.text:00401232 cmp [ebp+loc_key], cl
.text:00401235 jz loc_4012CF
.text:0040123B cmp [ebp+loc_key+1], cl
.text:0040123E jz loc_4012CF
.text:00401244 cmp [ebp+loc_key+2], cl
.text:00401247 jz loc_4012CF
.text:0040124D cmp [ebp+loc_key+3], cl
.text:00401250 jz short loc_4012CF
.text:00401252 cmp [ebp+loc_key], 31h
.text:00401256 jnz short loc_4012CF
.text:00401258 cmp [ebp+loc_key+1], 35h
.text:0040125C jnz short loc_4012CF
紧接代码(1),代码(2)要求 loc_key[i]!="0",其中i=0,1,2,3
其loc_key[0]="1" (0x31); loc_key[1] = "5" (0x35)
(3)
.text:0040126B movsx eax, [ebp+loc_key+2]
.text:0040126F sub eax, ecx
.text:00401271 mov [ebp+var_4], eax
.text:00401274 movsx eax, [ebp+loc_key]
.text:00401278 fild [ebp+var_4]
.text:0040127B sub eax, ecx
.text:0040127D mov [ebp+var_4], eax
.text:00401280 movsx eax, [ebp+loc_key+1]
.text:00401284 fild [ebp+var_4]
.text:00401287 sub eax, ecx
.text:00401289 mov [ebp+var_4], eax
.text:0040128C fidiv [ebp+var_4]
.text:0040128F movsx eax, [ebp+loc_key+3]
.text:00401293 sub eax, ecx
.text:00401295 mov [ebp+var_4], eax
.text:00401298 fsubp st(1), st
.text:0040129A fimul [ebp+var_4]
.text:0040129D fmul ds:flt_40711C
.text:004012A3 fstp [ebp+var_4]
//省略无关代码
.text:004012B3 fld [ebp+var_4]
.text:004012B6 fcomp ds:flt_407118
紧接代码(2),代码(3)要求下述等式成立
等式1>> (key[2] - key[0]/key[1])*key[3]*16.0=384.0
其中key[0~3]分别为loc_key[0~3]数字字符对应的数值,即
key[0] = 1
key[1] = 5
key[0],key[1]带入等式1并化简得到
等式2>> (key[2] - 0.2)*key[3]=24.0
假定key[2]取1到9,可遍历得到相应的key[3]值
[24.0/(i-0.2) for i in xrange(1,10)]
[30.0, 13.333333333333332, 8.571428571428571, 6.315789473684211, 5.0, 4.137931034482759, 3.5294117647058822, 3.076923076923077, 2.727272727272727]
由于key[3]为字符ASCII值减去0x30所得,即key[3] = 30.0 或 5.0 (相应地,key[2]=1 或 5)
可以得到两个有效key([1,5,5,5] 或 [1,5,1,30]),相应的key字符串为 "1555","151N"
0x06
题外,_WinMain@16 函数体逻辑如下
(1)窗体类"myWindowClass"注册,响应行数Hi_wndclass_fnWndProc_sub_401000
hIcon = windll.user32.LoadIconA(hInstance,0x65)
hCursor = windll.user32.LoadCursorA(0,0x7F00)
WNDCLASSEXA struc ; (sizeof=0x30, align=0x4)
00000000 cbSize dd 0x30
00000004 style dd 0
00000008 lpfnWndProc dd Hi_wndclass_fnWndProc_sub_401000
0000000C cbClsExtra dd NULL
00000010 cbWndExtra dd NULL
00000014 hInstance dd hInstance
00000018 hIcon dd hIcon
0000001C hCursor dd hCursor
00000020 hbrBackground dd 0x10
00000024 lpszMenuName dd NULL
00000028 lpszClassName dd "myWindowClass"
0000002C hIconSm dd hIcon
WNDCLASSEXA ends
windll.user32.RegisterClassExA()
SM_CXSCREEN=0
SM_CYSCREEN=1
hWnd = windll.user32.CreateWindowExA(
0,//dwExStyle
"myWindowClass",
"PEDIY CTF 2017",//WindowName
0x8A0000,//dwStyle
windll.user32.GetSystemMetrics(SM_CXSCREEN.0)/2-100,//X
windll.user32.GetSystemMetrics(SM_CYSCREEN.1)/2-100,//Y
0xFA,//nWith = 250
0xB4,//nHeight = 180
0,//hWndParent
0,//hMenu
hInstance,
0,//lpParam
)
(2)子对话窗体(resId:0x65)居中显示,响应函数Hi_DialogFunc_sub_401041
hDlg = windll.user32.CreateDialogParamA(
hInstance
0x65,//lpTemplateName
hWnd,//hWndParent
Hi_DialogFunc_sub_401041,//lpDialogFunc
0,//dwInitParam
)
windll.user32.SetWindowPos(
hDlg,
hWnd //hWndInsertAfter
0,//X
0,//Y
0,//cx
0,//cy
uFlags,//0x43 SWP_SHOWWINDOW.0x0040 SWP_NOSIZE.1 SWP_NOMOVE.2
}
windll.user32.ShowWindow(hWnd)
windll.user32.UpdateWindow(hWnd)
(3) 通过IsDiagloMessageA使得父、子响应函数
Hi_wndclass_fnWndProc_sub_401000与Hi_DialogFunc_sub_401041各司其职。
while windll.user32.GetMessageA(
&Msg,
0,//hWnd
0,//wMsgFilterMin
0,//wMsgFilterMax
):
if not windll.user32.IsDiagloMessageA(hDlg,&Msg):
windll.user32.TranslateMessage(&Msg)
windll.user32.DispatchMessageA(&Msg)
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创] KCTF 2022 Win. 第六题 约束与伪随机 6745
- [原创] KCTF 2021 Win. 第二题 排排坐 21175
- [原创] KCTF 2021 Win. 第一题 算力与攻击模式 4118
- 鸿蒙通识 26032
- [原创] KCTF 2021 Spr. 第二题 未选择的路 9250