[CISCN2021]华北区_ctf_re_imnotavirus
题目来源和附件
Written by Poilzero(blog:poilzero.cn)
题目来源:
题目附件:
https://poil.lanzoui.com/i0iImqjom6h
个人解题目录和部分所需程序:
https://poil.lanzoui.com/i9txPqz69pg
文件是一个用python写的程序并且使用pyinstaller打包难点在于
总体分解过程是step1-5
main.exe_extracted\PYZ-00.pyz_extracted\sign.pyc.encrypted
)得到源码
step23逆向成py文件
使用python38 pyinstxtractor.py:
python pyinstxtractor.py [filename]
Please run this script in Python39 to prevent extraction errors during unmarshalling
使用python39 pyinstxtractor.py:
python pyinstxtractor.py [filename]
[!] Error: Failed to decompress PYZ-00.pyz_extracted\__future__.pyc, probably encrypted. Extracting as is.
main.exe_extracted\main.pyc
使用python38 uncompyle6库(pip install uncompyle):uncompyle6 [org_filename] > [out_filename]
【*】修改pyc文件头,标其为python3.8的pyc文件
使用二进制编辑器打开(如01editor winhex),参考我自己写的python38写的程序的反汇编pyc修改前16个字节为
可以看到主文件其实调用了的是sign文件中的main()函数,因此下一步我们需要解密这个被加密的sign文件
step4解密sign核心源码
文件位于:
main.exe_extracted\PYZ-00.pyz_extracted\sign.pyc.encrypted
主办方提示:pyimod02_archive.py文件
定位文件在pyinstaller项目源码:
imnotavirus\pyinstaller-4.2\PyInstaller\loader\pyimod02_archive.py
以及逆向生成的pyc文件:
main.exe_extracted\pyimod02_archive.pyc
分析得知:pyimod02_archive.py中有解密函数,参考其调用规则,在该文件末编写如下代码
inf = open('sign.pyc.encrypted', 'rb')
c = Cipher()
buf = c.decrypt(inf.read())
buf = zlib.decompress(buf) # 查看这个代码文件能发现密文是用zlib压缩过的所以需要解压缩
out = open('sign.pyc', 'wb')
out.write(buf)
print('written down %n bytes' % len(buf))
inf.close()
out.close()
将相关文件移入main.exe_extracted
目录中
加密文件:main.exe_extracted\PYZ-00.pyz_extracted\sign.pyc.encrypted
解密文件:imnotavirus\pyinstaller-4.2\PyInstaller\loader\pyimod02_archive.py
使用python39进入main.exe_extracted
目录中,依次运行
使用pyc加载相关的文件所以要在逆向目录中(比如密钥文件):pyimod02_archive.pyc
pyimod02_archive.py
提示written down 3457 bytes
代表正确生成了文件
在main.exe_extracted
目录中的sign.py就是解压后的文件,参考前面的 <u>“【*】修改pyc文件头,标其为python3.8的pyc文件”</u>
在文件最开始的地方插入十六个同前面的字节,然后用python38反编译得到核心源码uncompyle6 sign.pyc > sign.py
核心代码如下
# uncompyle6 version 3.7.4
# Python bytecode 3.8 (3413)
# Decompiled from: Python 3.8.5 (default, Sep 3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: sign.py
import ctypes, urllib, base64, hashlib, ast
def ppp(bbb):
qaq = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(bbb)), ctypes.c_int(12288), ctypes.c_int(64))
bbb[31:35] = (qaq + 59).to_bytes(4, 'little')
bbb[36:40] = (qaq + 178).to_bytes(4, 'little')
qwq = (ctypes.c_char * len(bbb)).from_buffer(bbb)
eval(base64.b64decode('Y3R5cGVzLndpbmRsbC5rZXJuZWwzMi5SdGxNb3ZlTWVtb3J5KGN0eXBlcy5jX3VpbnQzMihxYXEpLHF3cSxjdHlwZXMuY19pbnQobGVuKGJiYikpKQ==').decode())
handle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint32(qaq), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle), ctypes.c_int(-1))
def aaa(ttt, ggg):
ggg = hashlib.md5(ggg).hexdigest()
ttt = base64.b64decode(ttt)
result = b''
ggg_len = len(ggg)
box = list(range(256))
j = 0
for i in range(256):
j = (j + box[i] + ord(ggg[(i % ggg_len)])) % 256
box[i], box[j] = box[j], box[i]
else:
i = j = 0
for iii in ttt:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
k = iii ^ box[((box[i] + box[j]) % 256)]
result += bytes([k])
else:
return result
def main():
ctypes.windll.kernel32.VirtualAlloc.restyle = ctypes.c_uint32
fff = input('Your input: ')
b = 'pB2M/eG2iz1pB4kej4yXXCYvTFV3b/6NDPvMVc+iOs2QwI7Tg7QcItIK6KtB5seaZhd67NGYh6xyMPAocLhd0NeJhweg5/rsEuYnzxFxqMrysaizRAiD6HQhe50rwF5UnByay04giUxuLxy6zL8me5sAQqaUAuCv0c1EsDKBxv1B1zV8MEDav5bkgsTd2t3X3Jt0+lfGKk98bxg1FIXoUhtyZjhV489SpMi+Gzs2+/zaZ0d7p12KoppTYPNs3sj9l74Q8EJPYIAecUEnMSmKDF7yPaKIFloCdW5ghVaSeiaskr5OzfzfeccpvRPevL7PW9uW1R8WmcW2oWjN9aWsinwG2Gk1B7JPa+HusBGpIxxSQhK0wBrEjQpYlIMC7fTpFZca373+p/A2oXuaXqfmOoWtE62JCM74tWqZFrSWyLdnu1/vHaClrzcdzpHLum9shEOcNHYi88Dj11mYufJxH/sEx0CBtWkTCHwEhxVs1sYkGBHlDFUpFbfpY0UagbyPJdq+bmXBdmLKEhJ/M/2cCjmsjuma6IKvo+riA7/B8+T3GB06x31G5tibi3rJMDb4bVWBswzI3gg06mc4Q9EW5dQ4+/SRKbVoYhAfbGKlBeuxSIARKzSAuJPlfm+dmJ6pHx9a4qek2UIEKr4zxA0bSMALoYOSETDF1JWZX+K0HEJLY/hXajmzq5qSTX0EAKBLJtIPkJ0e+XsaQCXyhy4Cg8mYNlQGIORNo5vyNe4QPAD8d3GKr/PZnEMwJ5WsgyoSBOGDke4PGUJd70thEyGHKN9QfTXWknC8HBZdcEojvtC3Prj7LlxXI6y8uZ7ie/1HltGogj3EsUkqU0d3WDuBPZec1Tzj/7Vs44MFGRjEJ0IuSA0U0vOCShyeHUB23qhrXqODsrO/t+s/Zohmd2H0xS46qdoquQj8L1RY2fCt3H0US3Wffk0FKf7qYboKeW/7vlkOYlchgP/HXf0Mfo5gBXhJg3e9jGJ8K5J0gt6Zra9dhPINGgekDMIoxXE='
c = aaa(b, 'blackhand'.encode('utf-8'))
c = ast.literal_eval("b'" + c.decode().strip() + "'")
qaq = eval(base64.b64decode('Y3R5cGVzLndpbmRsbC5rZXJuZWwzMi5WaXJ0dWFsQWxsb2MoY3R5cGVzLmNfaW50KDApLCBjdHlwZXMuY19pbnQobGVuKGZmZikpLCBjdHlwZXMuY19pbnQoMTIyODgpLCBjdHlwZXMuY19pbnQoNjQpKQ==').decode())
qwq = (ctypes.c_char * (len(fff) + 1)).from_buffer(bytearray(fff.encode()) + bytes([0]))
eval(base64.b64decode('Y3R5cGVzLndpbmRsbC5rZXJuZWwzMi5SdGxNb3ZlTWVtb3J5KGN0eXBlcy5jX3VpbnQzMihxYXEpLHF3cSxjdHlwZXMuY19pbnQobGVuKGZmZikpKQ==').decode())
c = bytearray(c)
c[55:59] = qaq.to_bytes(4, 'little')
ppp(c)
r = ctypes.create_string_buffer(len(fff))
ctypes.windll.kernel32.ReadProcessMemory(ctypes.windll.kernel32.GetCurrentProcess(), ctypes.c_uint32(qaq), ctypes.byref(r), ctypes.c_ulong(len(fff)), 0)
if r.raw == b'J\x04`~~s Q"Y!C [j\x05e\x06aB&N#B!E Qp\\ S{\x05{\x05{\x05':
print('Yes! You got it!')
else:
print('Nope. Try harder :)')
# okay decompiling sign.pyc
step5注册机
sign源码审计
审计后发现代码内容主要做以下几件事
读取输入值
*使用win32api操作
把输入值和汇编形式的指针函数写入内存中
使用线程调用这个指针函数从而加密输入值
最后把加密结果和一个量比较判断是否正确
其中指针函数在ppp()函数中,我写了个myproof函数把这个指针函数作为一个文件保存下来
提示如下时代码正常运行
require:
python3.9 x32版本
标准库:ctypes, urllib, base64, hashlib, ast
Your input: 1111
> written down 191 bytes
> written in 0x3950000
Nope. Try harder :)
Process finished with exit code 0
接下来就是审计用汇编写的指针函数了
已添加注释如下,也可在附件中查看
# uncompyle6 version 3.7.4
# Python bytecode 3.8 (3413)
# Decompiled from: Python 3.8.5 (default, Sep 3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: sign.py
import ctypes, urllib, base64, hashlib, ast
def my_proof(QAQ, add):
# save qaq function
out = open('qaq_function', 'wb')
out.write(QAQ)
out.close(),print('> written down {} bytes'.format(len(QAQ)))
print('> written in {}'.format(hex(add)))
def getStringFromMem(source, length):
r = ctypes.create_string_buffer(length)
ctypes.windll.kernel32.ReadProcessMemory(
ctypes.windll.kernel32.GetCurrentProcess() # hinstance
, ctypes.c_uint32(source) # from address
, ctypes.byref(r) # destination address
, ctypes.c_ulong(length) # nSize
# print('in getStringFromMem() qaq\'s address is {}'.format(hex(source)))
return r.raw
# converted by c(bbb)
def ppp(bbb):
# qaq = malloc(len(bbb))
qaq = ctypes.windll.kernel32.VirtualAlloc(
ctypes.c_int(0) # destination address
, ctypes.c_int(len(bbb)) # dwSize
, ctypes.c_int(12288) # type of allocation
, ctypes.c_int(64)
) # type of access protection
bbb[31:35] = (qaq + 59).to_bytes(4, 'little')
bbb[36:40] = (qaq + 178).to_bytes(4, 'little')
# qwq = bbb
qwq = (ctypes.c_char * len(bbb)).from_buffer(bbb)
# qaq = qwq (=bbb)
ctypes.windll.kernel32.RtlMoveMemory(
ctypes.c_uint32(qaq) # destination address
,qwq # source address
,ctypes.c_int(len(bbb)) # nSize
# bbb is code written to mem-add at qaq
my_proof(bbb, qaq) # to touch qaq=qwq=bbb written by me
####### threadprocess
# qaq is a function!!!
handle = ctypes.windll.kernel32.CreateThread(
ctypes.c_int(0) # must be NULL
, ctypes.c_int(0) # 0 means createThread STACK_SIZE_PARAM_IS_A_RESERVATION means as virtual memeory
, ctypes.c_uint32(qaq) # function pointer!!!!
, ctypes.c_int(0) # function's param lpvThreadParam
, ctypes.c_int(0) # type of CreateThread
, ctypes.pointer(ctypes.c_int(0)) # lpRecevedReternValue if 0 it will not return to it
ctypes.windll.kernel32.WaitForSingleObject(
ctypes.c_int(handle)
, ctypes.c_int(-1)
return None
return is constance
def aaa(ttt, ggg):
ggg = hashlib.md5(ggg).hexdigest() # ggg = md5(ggg,16,little)
ttt = base64.b64decode(ttt)
##########
result = b''
ggg_len = len(ggg)
box = list(range(256))
j = 0
for i in range(256):
j = (j + box[i] + ord(ggg[(i % ggg_len)])) % 256
box[i], box[j] = box[j], box[i]
else:
i = j = 0
for iii in ttt:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
k = iii ^ box[((box[i] + box[j]) % 256)]
result += bytes([k])
else:
return result
def main():
ctypes.windll.kernel32.VirtualAlloc.restyle = ctypes.c_uint32
# fff = 'Y3sImD3f1n2t3ly2v1ru5y0u2r3fck3dh2h2h2'
fff = input('Your input: ')
b = 'pB2M/eG2iz1pB4kej4yXXCYvTFV3b/6NDPvMVc+iOs2QwI7Tg7QcItIK6KtB5seaZhd67NGYh6xyMPAocLhd0NeJhweg5/rsEuYnzxFxqMrysaizRAiD6HQhe50rwF5UnByay04giUxuLxy6zL8me5sAQqaUAuCv0c1EsDKBxv1B1zV8MEDav5bkgsTd2t3X3Jt0+lfGKk98bxg1FIXoUhtyZjhV489SpMi+Gzs2+/zaZ0d7p12KoppTYPNs3sj9l74Q8EJPYIAecUEnMSmKDF7yPaKIFloCdW5ghVaSeiaskr5OzfzfeccpvRPevL7PW9uW1R8WmcW2oWjN9aWsinwG2Gk1B7JPa+HusBGpIxxSQhK0wBrEjQpYlIMC7fTpFZca373+p/A2oXuaXqfmOoWtE62JCM74tWqZFrSWyLdnu1/vHaClrzcdzpHLum9shEOcNHYi88Dj11mYufJxH/sEx0CBtWkTCHwEhxVs1sYkGBHlDFUpFbfpY0UagbyPJdq+bmXBdmLKEhJ/M/2cCjmsjuma6IKvo+riA7/B8+T3GB06x31G5tibi3rJMDb4bVWBswzI3gg06mc4Q9EW5dQ4+/SRKbVoYhAfbGKlBeuxSIARKzSAuJPlfm+dmJ6pHx9a4qek2UIEKr4zxA0bSMALoYOSETDF1JWZX+K0HEJLY/hXajmzq5qSTX0EAKBLJtIPkJ0e+XsaQCXyhy4Cg8mYNlQGIORNo5vyNe4QPAD8d3GKr/PZnEMwJ5WsgyoSBOGDke4PGUJd70thEyGHKN9QfTXWknC8HBZdcEojvtC3Prj7LlxXI6y8uZ7ie/1HltGogj3EsUkqU0d3WDuBPZec1Tzj/7Vs44MFGRjEJ0IuSA0U0vOCShyeHUB23qhrXqODsrO/t+s/Zohmd2H0xS46qdoquQj8L1RY2fCt3H0US3Wffk0FKf7qYboKeW/7vlkOYlchgP/HXf0Mfo5gBXhJg3e9jGJ8K5J0gt6Zra9dhPINGgekDMIoxXE='
c = aaa(b, 'blackhand'.encode('utf-8'))
# ast.literal_eval equal try-catch-mode eval()
# strip() 去除首尾的所有 或\n
c = ast.literal_eval("b'" + c.decode().strip() + "'") # c is constance
# qaq = malloc(len(fff))
qaq = ctypes.windll.kernel32.VirtualAlloc(
ctypes.c_int(0) # destination address
, ctypes.c_int(len(fff)) # dwSize
, ctypes.c_int(12288) # type of allocation
, ctypes.c_int(64) # type of access protection
# qwq=fff+'0'
qwq = (ctypes.c_char * (len(fff) + 1)).from_buffer(bytearray(fff.encode()) + bytes([0]))
# qaq = qwq(=fff+'\x0')
ctypes.windll.kernel32.RtlMoveMemory(
ctypes.c_uint32(qaq) # destination address
,qwq # source address
,ctypes.c_int(len(fff)) # nSize
c variable change start
c = bytearray(c) # transefer to bytes list struct (like list)
# c[55:59] = qaq_address[0:4]
c[55:59] = qaq.to_bytes(4, 'little')
# print(getStringFromMem(qaq,len(fff)))
ppp(c)
# print(getStringFromMem(qaq,len(fff)))
change end
# r.raw = qaq
r = ctypes.create_string_buffer(len(fff))
ctypes.windll.kernel32.ReadProcessMemory(
ctypes.windll.kernel32.GetCurrentProcess() # hinstance
, ctypes.c_uint32(qaq) # from address
, ctypes.byref(r) # destination address
, ctypes.c_ulong(len(fff)) # nSize
# compare
if r.raw == b'J\x04`~~s Q"Y!C [j\x05e\x06aB&N#B!E Qp\\ S{\x05{\x05{\x05':
print('Yes! You got it!')
else:
print('Nope. Try harder :)')
# okay decompiling sign.pyc
main()
指针函数汇编审计
ida打开qaq_function发现有乱码:
seg000:00000000 ; ===========================================================================
seg000:00000000
seg000:00000000 ; Segment type: Pure code
seg000:00000000 seg000 segment byte public 'CODE' use32
seg000:00000000 assume cs:seg000
seg000:00000000 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
seg000:00000000 push ebp
seg000:00000001 mov ebp, esp
seg000:00000003 sub esp, 0E4h
seg000:00000009 push ebx
seg000:0000000A push esi
seg000:0000000B push edi
seg000:0000000C lea edi, [ebp-0E4h]
seg000:00000012 mov ecx, 39h ; '9'
seg000:00000017 mov eax, 0CCCCCCCCh
seg000:0000001C rep stosd
seg000:0000001E mov eax, 3BB003Bh
seg000:00000023 mov ecx, 3BB00B2h
seg000:00000028 sub ecx, eax
seg000:0000002A
seg000:0000002A loc_2A: ; CODE XREF: seg000:00000032↓j
seg000:0000002A mov ebx, [eax]
seg000:0000002C xor ebx, 77h
seg000:0000002F mov [eax], ebx
seg000:00000031 inc eax
seg000:00000032 loop loc_2A
seg000:00000034 mov dword ptr [ebp+8], 3BA0000h
seg000:0000003B mov al, 32h ; '2'
seg000:0000003B ; ---------------------------------------------------------------------------
seg000:0000003D db 8Fh, 2 dup(77h)
seg000:00000040 db 77h ; w
seg000:00000041 db 77h, 0B0h, 32h
seg000:00000044 dd 7777779Bh, 0FC7E9C77h, 0B7F49B32h, 9B32FE76h, 747F32FCh
seg000:00000044 dd 0C9789B32h, 3BEF27Fh, 8F32FC7Ch, 0FE76B7F4h, 0A89C8F32h
seg000:00000044 dd 779732B0h, 9C777777h, 9732FC7Eh, 0FE75B7F4h, 32FC9732h
seg000:00000044 dd 8F324C97h, 32FC5B0Ah, 9732747Fh, 0F47FC978h, 22FC6486h
seg000:00000044 dd 9722747Fh, 32FC7DFFh, 9732747Fh, 763FC978h, 0FC4086F4h
seg000:00000044 dd 22747F22h, 763DFF97h, 5E5FB49Ch, 0E4C4815Bh, 8B000000h
seg000:000000BC db 0E5h, 5Dh, 0C3h
seg000:000000BC seg000 ends
seg000:000000BC
seg000:000000BC
seg000:000000BC end
其中smc代码,修改了运行时的程序代码,规则是与0x77异或,即以下代码
seg000:0000001E mov eax, 3BB003Bh
seg000:00000023 mov ecx, 3BB00B2h
seg000:00000028 sub ecx, eax
seg000:0000002A
seg000:0000002A loc_2A: ; CODE XREF: seg000:00000032↓j
seg000:0000002A mov ebx, [eax]
seg000:0000002C xor ebx, 77h
seg000:0000002F mov [eax], ebx
seg000:00000031 inc eax
seg000:00000032 loop loc_2A
编写代码直接代替执行异或,对文件直接修改生成正确的运行时指针函数
l = 0x3b
r = 0xb2
fi = open('qaq_function', 'rb')
fo = open('qaq_function_smced', 'wb')
cipher = fi.read()
for i in range(len(cipher)):
if i>=0x3b and i<0xb2:
per = cipher[i]^0x77
else:
per = cipher[i]
per = hex(per)
per = "b'\\"+per[1:]+"'"
if len(per)==6:
per = per[:-2]+'0'+per[-2:]
print('> written byte:', per)
per = eval(per)
fo.write(per)
fi.close(),fo.close()
得到qaq_function_smced文件ida打开如下:
跳转流程:
loc_54-》loc_6C(花指令本质上是强制跳转)-》loc_7E-》
seg000:00000000 ; ===========================================================================
seg000:00000000
seg000:00000000 ; Segment type: Pure code
seg000:00000000 seg000 segment byte public 'CODE' use32
seg000:00000000 assume cs:seg000
seg000:00000000 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
seg000:00000000 push ebp
seg000:00000001 mov ebp, esp
seg000:00000003 sub esp, 0E4h
seg000:00000009 push ebx
seg000:0000000A push esi
seg000:0000000B push edi
seg000:0000000C lea edi, [ebp-0E4h]
seg000:00000012 mov ecx, 39h ; '9'
seg000:00000017 mov eax, 0CCCCCCCCh
seg000:0000001C rep stosd
seg000:0000001E mov eax, 3BB003Bh
seg000:00000023 mov ecx, 3BB00B2h
seg000:00000028 sub ecx, eax
seg000:0000002A
seg000:0000002A loc_2A: ; CODE XREF: seg000:00000032↓j
seg000:0000002A mov ebx, [eax]
seg000:0000002C xor ebx, 77h
seg000:0000002F mov [eax], ebx
seg000:00000031 inc eax
seg000:00000032 loop loc_2A
seg000:00000034 mov dword ptr [ebp+8], 3BA0000h
seg000:0000003B mov dword ptr [ebp-8], 0
seg000:00000042 mov dword ptr [ebp-14h], 0
seg000:00000049 jmp short loc_54
seg000:0000004B ; ---------------------------------------------------------------------------
seg000:0000004B
seg000:0000004B loc_4B: ; CODE XREF: seg000:0000006A↓j
seg000:0000004B mov eax, [ebp-14h]
seg000:0000004E add eax, 1
seg000:00000051 mov [ebp-14h], eax
seg000:00000054
seg000:00000054 loc_54: ; CODE XREF: seg000:00000049↑j
seg000:00000054 mov eax, [ebp+8]
seg000:00000057 add eax, [ebp-14h]
seg000:0000005A movsx ecx, byte ptr [eax]
seg000:0000005D test ecx, ecx
seg000:0000005F jz short loc_6C ; 花指令,其实是强制跳转jmp
seg000:00000061 mov eax, [ebp-8]
seg000:00000064 add eax, 1
seg000:00000067 mov [ebp-8], eax
seg000:0000006A jmp short loc_4B
seg000:0000006C ; ---------------------------------------------------------------------------
seg000:0000006C
seg000:0000006C loc_6C: ; CODE XREF: seg000:0000005F↑j
seg000:0000006C mov dword ptr [ebp-20h], 0
seg000:00000073 jmp short loc_7E
seg000:00000075 ; ---------------------------------------------------------------------------
seg000:00000075
seg000:00000075 loc_75: ; CODE XREF: seg000:000000B0↓j
seg000:00000075 mov eax, [ebp-20h]
seg000:00000078 add eax, 2
seg000:0000007B mov [ebp-20h], eax
seg000:0000007E
seg000:0000007E loc_7E: ; CODE XREF: seg000:00000073↑j
seg000:0000007E mov eax, [ebp-20h]
seg000:00000081 cmp eax, [ebp-8]
seg000:00000084 jge short loc_B2
seg000:00000086 mov eax, [ebp+8]
seg000:00000089 add eax, [ebp-20h]
seg000:0000008C movsx ecx, byte ptr [eax]
seg000:0000008F xor ecx, 13h
seg000:00000092 mov edx, [ebp+8]
seg000:00000095 add edx, [ebp-20h]
seg000:00000098 mov [edx], cl
seg000:0000009A mov eax, [ebp+8]
seg000:0000009D add eax, [ebp-20h]
seg000:000000A0 movsx ecx, byte ptr [eax+1]
seg000:000000A4 xor ecx, 37h
seg000:000000A7 mov edx, [ebp+8]
seg000:000000AA add edx, [ebp-20h]
seg000:000000AD mov [edx+1], cl
seg000:000000B0 jmp short loc_75
seg000:000000B2 ; ---------------------------------------------------------------------------
seg000:000000B2
seg000:000000B2 loc_B2: ; CODE XREF: seg000:00000084↑j
seg000:000000B2 pop edi
seg000:000000B3 pop esi
seg000:000000B4 pop ebx
seg000:000000B5 add esp, 0E4h
seg000:000000BB mov esp, ebp
seg000:000000BD pop ebp
seg000:000000BE retn
seg000:000000BE seg000 ends
seg000:000000BE
seg000:000000BE
seg000:000000BE end
本质上是将输入值偶奇位分别于0x13和0x37进行异或,编写注册机:
s = 'J\x04`~~s Q"Y!C [j\x05e\x06aB&N#B!E Qp\\ S{\x05{\x05{\x05'
ans = ''
for i in range(len(s)):
per = ord(s[i])
if i%2 ==0:
ans += chr(per^0x13)
else:
ans += chr(per^0x37)
print(ans)