-
-
[原创]看雪 2016 CTF 第五题 Solution
-
发表于: 2016-11-10 18:06 2497
-
40KB 麻雀虽小,五脏俱全。
不知为何,这让想起了顾参数的顾桥教授给我们上量子力学时提的一句:"Less is More!"
6位密码,想不到比枚举更好的方法,直上Python跑出来。
(1)进门,跨过运行时环境初始化,进入作者写的代码 main 。
4012D0 start
401399 call _WinMain@16
.text:004012B4 push 0 ; dwInitParam
.text:004012B6 push offset DialogFunc ; lpDialogFunc
.text:004012BB push 0 ; hWndParent
.text:004012BD push 65h ; lpTemplateName
.text:004012BF push eax ; hInstance
.text:004012C0 call ds:DialogBox
(2)由(1)进入对话框消息处理,文本的获取不是GetWindowText 或 GetWindowLong,而是发送请求消息获取
.text:0040115B lea eax, [esp+120h+lParam]
.text:0040115F mov edi, 1
.text:00401164 push eax ; lParam
.text:00401165 push 0FFh ; wParam
.text:0040116A push WM_GETTEXT ; Msg
.text:0040116C push 3E9h ; nIDDlgItem
.text:00401171 push esi ; hDlg
.text:00401172 call ebx ; GetDlgItem
.text:00401174 mov ebp, ds:SendMessageA
.text:0040117A push eax ; hWnd
.text:0040117B call ebp ; SendMessa
(3)获取输入key后限定检测数字,后面要求长度为6
.text:00401187 cmp dl, 30h
.text:0040118A jl short loc_401198
.text:0040118C cmp dl, 39h
.text:0040118F jg short loc_401198
(4)随后通过key发散得到异或矩阵,对保护代码解密(只有对的key扩散的矩阵才能得到正确的解密)
Hi_decrypt_EncDigest_with_P1lpszKey_P2size_sub_401000 解密后 进行校验和检测以验证是否用正确的key解密出正确的结果。
执行解码的代码,提示成功 "success!youareclever."
.text:004011A3 lea ecx, [esp+120h+lParam]
.text:004011A7 push eax
.text:004011A8 push ecx
.text:004011A9 call Hi_decrypt_EncDigest_with_P1lpszKey_P2size_sub_401000
.text:004011AE add esp, 8
.text:004011B1 call Hi_CheckCrc_sub_4010C0
(5)完成保护功能后,再加密回去。
getXorFromKey 直接返回由key扩散后进一步得到的异或解密矩阵
checkXorM 检测用相应异或矩阵的结果校验值,不正确继续
从IDA提取的加密方法体
"""
用于从IDA提取保护的加密方法体
a = []
for i in xrange(0,0x80):
print "0x{:02X}, ".format(Byte(0x406030+i)),
if ((i + 1) % 0x10) == 0:
print ""
"""
CrcM = [0xF4, 0x12, 0x9D, 0x60, 0x45, 0xF8, 0x20, 0x6A, 0x6F, 0x67, 0x04, 0x71, 0xC0, 0x9B, 0x0C, 0x5A,
0x1D, 0x18, 0x6C, 0x96, 0x69, 0x01, 0x1C, 0xF4, 0x7F, 0x28, 0x5A, 0xFB, 0x29, 0x07, 0x40, 0x8B,
0xD3, 0xE1, 0xB1, 0x12, 0xFB, 0xCA, 0x7C, 0x89, 0xB9, 0x5A, 0x30, 0x70, 0x9D, 0x95, 0x2B, 0x95,
0x3C, 0x8D, 0x2E, 0x45, 0xEF, 0x70, 0xC6, 0xA3, 0xB9, 0xB2, 0x5A, 0x63, 0x5F, 0x03, 0x33, 0xB8,
0x64, 0x4A, 0x8F, 0xBC, 0xF7, 0x91, 0x69, 0x6A, 0x56, 0x2E, 0xD4, 0x6E, 0x82, 0x93, 0xE9, 0x76,
0xDC, 0xA3, 0x6C, 0x5E, 0x6B, 0x72, 0x64, 0x37, 0xE7, 0x15, 0x17, 0xAC, 0x64, 0x78, 0xD5, 0x4A,
0x60, 0x2D, 0xF0, 0x54, 0xA6, 0xF3, 0xE8, 0xE0, 0xE0, 0xB9, 0x8F, 0x85, 0x90, 0xE4, 0xEA, 0xD6,
0xBB, 0xB7, 0x15, 0x9E, 0x2A, 0x44, 0xE7, 0x31, 0x63, 0xAC, 0x80, 0x6C, 0x34, 0x82, 0xE9, 0xCF]
from ctypes import *
def getXorFromKey(keyi):
buf100 = [ i for i in xrange(0,0x100)]
cl = c_ubyte(0)
bl = c_ubyte(0)
dl = c_ubyte(0)
bufi = 0
ki = 0
while True:
cl.value = buf100[bufi]
bl.value = keyi[ki]
bl.value = bl.value + cl.value
dl.value = dl.value + bl.value
bl.value = buf100[dl.value]
buf100[bufi] = bl.value
buf100[dl.value] = cl.value
ki = ki + 1
if ki == 6:
ki = 0
bufi = bufi + 1
if bufi == 0x100:
break
XorM = []
for i in xrange(0,0x80):
bl.value = buf100[i]
dl.value = buf100[0xff-i]
dl.value = dl.value + bl.value
XorM.append(dl.value)
return XorM
def checkXorM(XorM):
global CrcM
dl = c_ubyte(0)
bl = c_ubyte(0)
DecM = []
esiedi = c_ulonglong(0)
for i in xrange(0,0x80):
dl.value = XorM[i]
bl.value = CrcM[i]
dl.value = dl.value ^ bl.value
esiedi.value = esiedi.value + dl.value
DecM.append(dl.value)
if esiedi.value == 0x2979:
return True
else:
return False
def Enum(cont = False):
for i in xrange(0,0x1000000):
keys = "{:06}".format(i)
keyi = [ord(ch) for ch in keys]
XorM = getXorFromKey(keyi)
if checkXorM(XorM):
print keys
if cont:
continue
else:
return
Enum(True) 得到结果 771535 (根据CPU情况,使用特定数量的并发线程分区枚举应该会快些)
不知为何,这让想起了顾参数的顾桥教授给我们上量子力学时提的一句:"Less is More!"
6位密码,想不到比枚举更好的方法,直上Python跑出来。
(1)进门,跨过运行时环境初始化,进入作者写的代码 main 。
4012D0 start
401399 call _WinMain@16
.text:004012B4 push 0 ; dwInitParam
.text:004012B6 push offset DialogFunc ; lpDialogFunc
.text:004012BB push 0 ; hWndParent
.text:004012BD push 65h ; lpTemplateName
.text:004012BF push eax ; hInstance
.text:004012C0 call ds:DialogBox
(2)由(1)进入对话框消息处理,文本的获取不是GetWindowText 或 GetWindowLong,而是发送请求消息获取
.text:0040115B lea eax, [esp+120h+lParam]
.text:0040115F mov edi, 1
.text:00401164 push eax ; lParam
.text:00401165 push 0FFh ; wParam
.text:0040116A push WM_GETTEXT ; Msg
.text:0040116C push 3E9h ; nIDDlgItem
.text:00401171 push esi ; hDlg
.text:00401172 call ebx ; GetDlgItem
.text:00401174 mov ebp, ds:SendMessageA
.text:0040117A push eax ; hWnd
.text:0040117B call ebp ; SendMessa
(3)获取输入key后限定检测数字,后面要求长度为6
.text:00401187 cmp dl, 30h
.text:0040118A jl short loc_401198
.text:0040118C cmp dl, 39h
.text:0040118F jg short loc_401198
(4)随后通过key发散得到异或矩阵,对保护代码解密(只有对的key扩散的矩阵才能得到正确的解密)
Hi_decrypt_EncDigest_with_P1lpszKey_P2size_sub_401000 解密后 进行校验和检测以验证是否用正确的key解密出正确的结果。
执行解码的代码,提示成功 "success!youareclever."
.text:004011A3 lea ecx, [esp+120h+lParam]
.text:004011A7 push eax
.text:004011A8 push ecx
.text:004011A9 call Hi_decrypt_EncDigest_with_P1lpszKey_P2size_sub_401000
.text:004011AE add esp, 8
.text:004011B1 call Hi_CheckCrc_sub_4010C0
(5)完成保护功能后,再加密回去。
getXorFromKey 直接返回由key扩散后进一步得到的异或解密矩阵
checkXorM 检测用相应异或矩阵的结果校验值,不正确继续
从IDA提取的加密方法体
"""
用于从IDA提取保护的加密方法体
a = []
for i in xrange(0,0x80):
print "0x{:02X}, ".format(Byte(0x406030+i)),
if ((i + 1) % 0x10) == 0:
print ""
"""
CrcM = [0xF4, 0x12, 0x9D, 0x60, 0x45, 0xF8, 0x20, 0x6A, 0x6F, 0x67, 0x04, 0x71, 0xC0, 0x9B, 0x0C, 0x5A,
0x1D, 0x18, 0x6C, 0x96, 0x69, 0x01, 0x1C, 0xF4, 0x7F, 0x28, 0x5A, 0xFB, 0x29, 0x07, 0x40, 0x8B,
0xD3, 0xE1, 0xB1, 0x12, 0xFB, 0xCA, 0x7C, 0x89, 0xB9, 0x5A, 0x30, 0x70, 0x9D, 0x95, 0x2B, 0x95,
0x3C, 0x8D, 0x2E, 0x45, 0xEF, 0x70, 0xC6, 0xA3, 0xB9, 0xB2, 0x5A, 0x63, 0x5F, 0x03, 0x33, 0xB8,
0x64, 0x4A, 0x8F, 0xBC, 0xF7, 0x91, 0x69, 0x6A, 0x56, 0x2E, 0xD4, 0x6E, 0x82, 0x93, 0xE9, 0x76,
0xDC, 0xA3, 0x6C, 0x5E, 0x6B, 0x72, 0x64, 0x37, 0xE7, 0x15, 0x17, 0xAC, 0x64, 0x78, 0xD5, 0x4A,
0x60, 0x2D, 0xF0, 0x54, 0xA6, 0xF3, 0xE8, 0xE0, 0xE0, 0xB9, 0x8F, 0x85, 0x90, 0xE4, 0xEA, 0xD6,
0xBB, 0xB7, 0x15, 0x9E, 0x2A, 0x44, 0xE7, 0x31, 0x63, 0xAC, 0x80, 0x6C, 0x34, 0x82, 0xE9, 0xCF]
from ctypes import *
def getXorFromKey(keyi):
buf100 = [ i for i in xrange(0,0x100)]
cl = c_ubyte(0)
bl = c_ubyte(0)
dl = c_ubyte(0)
bufi = 0
ki = 0
while True:
cl.value = buf100[bufi]
bl.value = keyi[ki]
bl.value = bl.value + cl.value
dl.value = dl.value + bl.value
bl.value = buf100[dl.value]
buf100[bufi] = bl.value
buf100[dl.value] = cl.value
ki = ki + 1
if ki == 6:
ki = 0
bufi = bufi + 1
if bufi == 0x100:
break
XorM = []
for i in xrange(0,0x80):
bl.value = buf100[i]
dl.value = buf100[0xff-i]
dl.value = dl.value + bl.value
XorM.append(dl.value)
return XorM
def checkXorM(XorM):
global CrcM
dl = c_ubyte(0)
bl = c_ubyte(0)
DecM = []
esiedi = c_ulonglong(0)
for i in xrange(0,0x80):
dl.value = XorM[i]
bl.value = CrcM[i]
dl.value = dl.value ^ bl.value
esiedi.value = esiedi.value + dl.value
DecM.append(dl.value)
if esiedi.value == 0x2979:
return True
else:
return False
def Enum(cont = False):
for i in xrange(0,0x1000000):
keys = "{:06}".format(i)
keyi = [ord(ch) for ch in keys]
XorM = getXorFromKey(keyi)
if checkXorM(XorM):
print keys
if cont:
continue
else:
return
Enum(True) 得到结果 771535 (根据CPU情况,使用特定数量的并发线程分区枚举应该会快些)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
- [原创] KCTF 2022 Win. 第六题 约束与伪随机 6745
- [原创] KCTF 2021 Win. 第二题 排排坐 21175
- [原创] KCTF 2021 Win. 第一题 算力与攻击模式 4118
- 鸿蒙通识 26032
- [原创] KCTF 2021 Spr. 第二题 未选择的路 9250
看原图
赞赏
雪币:
留言: