Back
Featured image of post Reverse from 1 to 2

Reverse from 1 to 2

BUUOJ 继续学习 Reverse,最后顺便记录了两个 pycdc 的 bug

[NPUCTF2020]BasicASM

纯考察汇编的题目,有考虑想办法改成正确的汇编形式然后编译用ida看,但感觉就失去意义了,于是硬啃汇编

00007FF7A8AC5A50  push        rbp  
00007FF7A8AC5A52  push        rdi  
00007FF7A8AC5A53  sub         rsp,238h  
00007FF7A8AC5A5A  lea         rbp,[rsp+20h]  
00007FF7A8AC5A5F  mov         rdi,rsp  
00007FF7A8AC5A62  mov         ecx,8Eh  
00007FF7A8AC5A67  mov         eax,0CCCCCCCCh  
00007FF7A8AC5A6C  rep stos    dword ptr [rdi]  
00007FF7A8AC5A6E  mov         rax,qword ptr [__security_cookie (07FF7A8AD3018h)]  
00007FF7A8AC5A75  xor         rax,rbp  
00007FF7A8AC5A78  mov         qword ptr [rbp+208h],rax  
00007FF7A8AC5A7F  lea         rcx,[__06A15900_ConsoleApplication@cpp (07FF7A8AD902Ah)]  
00007FF7A8AC5A86  call        __CheckForDebuggerJustMyCode (07FF7A8AC1122h)  
00007FF7A8AC5A8B  lea         rdx,[string "flag{this_is_a_fake_flag}" (07FF7A8ACF450h)]  
00007FF7A8AC5A92  lea         rcx,[flag]  
00007FF7A8AC5A96  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (07FF7A8AC15E1h)  
00007FF7A8AC5A9B  nop  
00007FF7A8AC5A9C  mov         dword ptr [p],0  
00007FF7A8AC5AA3  mov         i,0  
00007FF7A8AC5AAA  jmp         main+64h (07FF7A8AC5AB4h)  
00007FF7A8AC5AAC  mov         eax,i  
00007FF7A8AC5AAF  inc         eax  
00007FF7A8AC5AB1  mov         i,eax  
00007FF7A8AC5AB4  movsxd      rax,i  
00007FF7A8AC5AB8  mov         qword ptr [rbp+1F8h],rax  
00007FF7A8AC5ABF  lea         rcx,[flag]  
00007FF7A8AC5AC3  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::length (07FF7A8AC122Bh)  
00007FF7A8AC5AC8  mov         rcx,qword ptr [rbp+1F8h]  
00007FF7A8AC5ACF  cmp         rcx,rax  
00007FF7A8AC5AD2  jae         main+1B2h (07FF7A8AC5C02h)  ; 无符号数比较,大于或等于时跳转
00007FF7A8AC5AD8  mov         eax,i  
00007FF7A8AC5ADB  and         eax,1  ; 取最后1位
00007FF7A8AC5ADE  cmp         eax,1  ; 判断奇偶
00007FF7A8AC5AE1  jne         main+126h (07FF7A8AC5B76h)  ; 偶数跳转(不相等跳转)
00007FF7A8AC5AE7  movsxd      rax,i  
00007FF7A8AC5AEB  mov         rdx,rax  
00007FF7A8AC5AEE  lea         rcx,[flag]  
00007FF7A8AC5AF2  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator[] (07FF7A8AC1442h)  
00007FF7A8AC5AF7  movsx       eax,byte ptr [rax]  ; 取flag第i位
00007FF7A8AC5AFA  xor         eax,42h  ; 与0x42异或
00007FF7A8AC5AFD  mov         dword ptr [p],eax  ; 异或结果移到内存中
00007FF7A8AC5B00  mov         dl,30h  
00007FF7A8AC5B02  lea         rcx,[rbp+144h]  
00007FF7A8AC5B09  call        std::setfill<char> (07FF7A8AC1046h)  ; 用字符'0'进行填充
00007FF7A8AC5B0E  mov         qword ptr [rbp+1F8h],rax  
00007FF7A8AC5B15  mov         edx,2  
00007FF7A8AC5B1A  lea         rcx,[rbp+168h]  
00007FF7A8AC5B21  call        std::setw (07FF7A8AC10D2h)  ; 填充至2位
00007FF7A8AC5B26  mov         qword ptr [rbp+200h],rax  
00007FF7A8AC5B2D  lea         rdx,[std::hex (07FF7A8AC1488h)]  ; 以十六进制形式输出
00007FF7A8AC5B34  mov         rcx,qword ptr [__imp_std::cout (07FF7A8AD71C0h)]  
00007FF7A8AC5B3B  call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF7A8AD7160h)]  
00007FF7A8AC5B41  mov         rcx,qword ptr [rbp+200h]  
00007FF7A8AC5B48  mov         rdx,rcx  
00007FF7A8AC5B4B  mov         rcx,rax  
00007FF7A8AC5B4E  call        std::operator<<<char,std::char_traits<char>,__int64> (07FF7A8AC12F8h)  
00007FF7A8AC5B53  mov         rcx,qword ptr [rbp+1F8h]  
00007FF7A8AC5B5A  mov         rdx,rcx  
00007FF7A8AC5B5D  mov         rcx,rax  
00007FF7A8AC5B60  call        std::operator<<<char,std::char_traits<char>,char> (07FF7A8AC11A4h)  
00007FF7A8AC5B65  mov         edx,dword ptr [p]  
00007FF7A8AC5B68  mov         rcx,rax  
00007FF7A8AC5B6B  call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF7A8AD7158h)]  
00007FF7A8AC5B71  jmp         main+1ADh (07FF7A8AC5BFDh)  
00007FF7A8AC5B76  movsxd      rax,i  ; 偶数时跳转到这里,与奇数唯一的区别为没有异或运算
00007FF7A8AC5B7A  mov         rdx,rax  
00007FF7A8AC5B7D  lea         rcx,[flag]  
00007FF7A8AC5B81  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator[] (07FF7A8AC1442h)  
00007FF7A8AC5B86  movsx       eax,byte ptr [rax]  
00007FF7A8AC5B89  mov         dword ptr [p],eax  
00007FF7A8AC5B8C  mov         dl,30h  
00007FF7A8AC5B8E  lea         rcx,[rbp+194h]  
00007FF7A8AC5B95  call        std::setfill<char> (07FF7A8AC1046h)  
00007FF7A8AC5B9A  mov         qword ptr [rbp+1F8h],rax  
00007FF7A8AC5BA1  mov         edx,2  
00007FF7A8AC5BA6  lea         rcx,[rbp+1B8h]  
00007FF7A8AC5BAD  call        std::setw (07FF7A8AC10D2h)  
00007FF7A8AC5BB2  mov         qword ptr [rbp+200h],rax  
00007FF7A8AC5BB9  lea         rdx,[std::hex (07FF7A8AC1488h)]  
00007FF7A8AC5BC0  mov         rcx,qword ptr [__imp_std::cout (07FF7A8AD71C0h)]  
00007FF7A8AC5BC7  call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF7A8AD7160h)]  
00007FF7A8AC5BCD  mov         rcx,qword ptr [rbp+200h]  
00007FF7A8AC5BD4  mov         rdx,rcx  
00007FF7A8AC5BD7  mov         rcx,rax  
00007FF7A8AC5BDA  call        std::operator<<<char,std::char_traits<char>,__int64> (07FF7A8AC12F8h)  
00007FF7A8AC5BDF  mov         rcx,qword ptr [rbp+1F8h]  
00007FF7A8AC5BE6  mov         rdx,rcx  
00007FF7A8AC5BE9  mov         rcx,rax  
00007FF7A8AC5BEC  call        std::operator<<<char,std::char_traits<char>,char> (07FF7A8AC11A4h)  
00007FF7A8AC5BF1  mov         edx,dword ptr [p]  
00007FF7A8AC5BF4  mov         rcx,rax  
00007FF7A8AC5BF7  call        qword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF7A8AD7158h)]  
00007FF7A8AC5BFD  jmp         main+5Ch (07FF7A8AC5AACh)  
00007FF7A8AC5C02  mov         dword ptr [rbp+1E4h],0  
00007FF7A8AC5C0C  lea         rcx,[flag]  
00007FF7A8AC5C10  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (07FF7A8AC1302h)  
00007FF7A8AC5C15  mov         eax,dword ptr [rbp+1E4h]  
00007FF7A8AC5C1B  mov         edi,eax  
00007FF7A8AC5C1D  lea         rcx,[rbp-20h]  
00007FF7A8AC5C21  lea         rdx,[__xt_z+540h (07FF7A8ACEFE0h)]  
00007FF7A8AC5C28  call        _RTC_CheckStackVars (07FF7A8AC1596h)  
00007FF7A8AC5C2D  mov         eax,edi  
00007FF7A8AC5C2F  mov         rcx,qword ptr [rbp+208h]  
00007FF7A8AC5C36  xor         rcx,rbp  
00007FF7A8AC5C39  call        __security_check_cookie (07FF7A8AC1190h)  
00007FF7A8AC5C3E  lea         rsp,[rbp+218h]  
00007FF7A8AC5C45  pop         rdi  
00007FF7A8AC5C46  pop         rbp  
00007FF7A8AC5C47  ret  

简单的说,过程就是一个循环,根据 i 的奇偶进行判断,是否与 0x42 进行异或,然后将结果以 2 位十六进制输出,所以只需要进行反向求解即可

from libnum import n2s
cipher = n2s(0x662e61257b26301d7972751d6b2c6f355f3a38742d74341d61776d7d7d)
for i in range(len(cipher)):
    if i & 1 == 1:
        print (chr(cipher[i] ^ 0x42), end = '')
    else:
        print (chr(cipher[i]), end = '')
# flag{d0_y0u_know_x86-64_a5m?}

[watevrCTF 2019]Repyc

010看一眼,发现文件头好像没什么问题,直接用 uncompyle6 转成python文件

和VN的题一样,变量都成了乱码,阅读一下然后改一改

zero = 0
one = 1
two = 2

def function(op):
    i = zero
    list_a = [zero] * two ** (two * two) # [0] * 16
    list_b = [zero] * 100
    list_c = []
    while op[i][zero] != 'nop':
        print (i, op[i])
        cur = op[i][zero].lower()
        args = op[i][one:]
        if cur == 'add':
            list_a[args[zero]] = list_a[args[one]] + list_a[args[two]]
        elif cur == 'xor':
            list_a[args[zero]] = list_a[args[one]] ^ list_a[args[two]]
        elif cur == 'sub':
            list_a[args[zero]] = list_a[args[one]] - list_a[args[two]]
        elif cur == 'mul':
            list_a[args[zero]] = list_a[args[one]] * list_a[args[two]]
        elif cur == 'div':
            list_a[args[zero]] = list_a[args[one]] / list_a[args[two]]
        elif cur == 'and':
            list_a[args[zero]] = list_a[args[one]] & list_a[args[two]]
        elif cur == 'or':
            list_a[args[zero]] = list_a[args[one]] | list_a[args[two]]
        elif cur == 'nothing':
            list_a[args[zero]] = list_a[args[zero]]
        elif cur == 'mov':
            list_a[args[zero]] = args[one]
        elif cur == 'set_a':
            list_a[args[zero]] = list_b[args[one]]
        elif cur == 'clear':
            list_a[args[zero]] = zero
        elif cur == 'input_b':
            list_b[args[zero]] = input(list_a[args[one]])
        elif cur == 'print_a':
            print(list_a[args[zero]])
        elif cur == 'c_pop':
            i = list_c.pop()
        elif cur == 'append_c':
            list_a[7] = zero
            for j in range(len(list_a[args[zero]])):
                if list_a[args[zero]] != list_a[args[one]]:
                    list_a[7] = one
                    i = list_a[args[two]]
                    list_c.append(i)
        elif cur == 'xor_a':
            str_next = ''
            for j in range(len(list_a[args[zero]])):
                str_next += chr(ord(list_a[args[zero]][j]) ^ list_a[args[one]])
            list_a[args[zero]] = str_next
        elif cur == 'sub_a':
            str_next = ''
            for j in range(len(list_a[args[zero]])):
                str_next += chr(ord(list_a[args[zero]][j]) - list_a[args[one]])
            list_a[args[zero]] = str_next
        print (list_a)
        print (list_b)
        print (list_c)
        print ()
        i += one


function(
    [
        [ 'mov', zero, 'Authentication token: '],
        # 将这个字符串放到list a的0号位置
        [ 'input_b', zero, zero],
        # 将输入放到list b的0号位置
        [ 'mov', 6, 'á×äÓâæíäàßåÉÛãåäÉÖÓÉäàÓÉÖÓåäÉÓÚÕæïèäßÙÚÉÛÓäàÙÔÉÓâæÉàÓÚÕÓÒÙæäàÉäàßåÉßåÉäàÓÉÚÓáÉ·Ôâ×ÚÕÓÔɳÚÕæïèäßÙÚÉÅä×ÚÔ×æÔÉ×Úïá×ïåÉßÉÔÙÚäÉæÓ×ÜÜïÉà×âÓÉ×ÉÑÙÙÔÉâßÔÉÖãäÉßÉæÓ×ÜÜïÉÓÚÞÙïÉäàßåÉåÙÚÑÉßÉàÙèÓÉïÙãÉáßÜÜÉÓÚÞÙïÉßäÉ×åáÓÜÜ\x97ÉïÙãäãÖÓ\x9aÕÙÛ\x99á×äÕà©â«³£ï²ÕÔÈ·±â¨ë'],
        # 将这个字符串放到list a的6号位置
        [ 'mov', two, two ** (3 * two + one) - two ** (two + one)],
        # 将120放到list a的2号位置
        [ 'mov', 4, 15],
        # 将15放到list a的4号位置
        [ 'mov', 3, one],
        # 将1放到list a的3号位置
        [ 'mul', two, two, 3],
        # list a的2号位置等于2号位置*3号位置,即不变
        [ 'add', two, two, 4],
        # list a的2号位置等于2号位置+4号位置,即120变为135
        [ 'nothing', zero, two],
        [ 'clear', 3],
        # list a的3号位置清零
        [ 'xor_a', 6, 3],
        # 6号位置中每一个字符与3异或
        [ 'mov', zero, 'Thanks.'],
        [ 'mov', one, 'Authorizing access...'],
        [ 'print_a', zero],
        [ 'set_a', zero, zero],
        [ 'xor_a', zero, two], # 输入异或135
        [ 'sub_a', zero, 4], # 输入减15
        [ 'mov', 5, 19],
        [ 'append_c', zero, 6, 5],
        [ 'print_a', one],
        [ 'nop'],
        [ 'mov', one, 'Access denied!'],
        [ 'print_a', one],
        [ 'nop']
    ]
)

将过程变量输出当作动调,就比较容易看懂每条指令在干什么了

最后发现有用的就是异或135和减15,猜flag头是 watevr,果然和密文前6个字符对上了

所以直接一个解密就行

cipher = 'á×äÓâæíäàßåÉÛãåäÉÖÓÉäàÓÉÖÓåäÉÓÚÕæïèäßÙÚÉÛÓäàÙÔÉÓâæÉàÓÚÕÓÒÙæäàÉäàßåÉßåÉäàÓÉÚÓáÉ·Ôâ×ÚÕÓÔɳÚÕæïèäßÙÚÉÅä×ÚÔ×æÔÉ×Úïá×ïåÉßÉÔÙÚäÉæÓ×ÜÜïÉà×âÓÉ×ÉÑÙÙÔÉâßÔÉÖãäÉßÉæÓ×ÜÜïÉÓÚÞÙïÉäàßåÉåÙÚÑÉßÉàÙèÓÉïÙãÉáßÜÜÉÓÚÞÙïÉßäÉ×åáÓÜÜ\x97ÉïÙãäãÖÓ\x9aÕÙÛ\x99á×äÕà©â«³£ï²ÕÔÈ·±â¨ë'

for c in cipher:
    print (chr((ord(c) + 15) ^ 135), end = '')
    
# watevr{this_must_be_the_best_encryption_method_evr_henceforth_this_is_the_new_Advanced_Encryption_Standard_anyways_i_dont_really_have_a_good_vid_but_i_really_enjoy_this_song_i_hope_you_will_enjoy_it_aswell!_youtube.com/watch?v=E5yFcdPAGv0}

[watevrCTF 2019]esreveR

用ida打开后,发现大量与输入无关的计算,于是决定先静态跟踪一下输入,然后再动调看过程数据

和输入有关的大概是这些(动调后写的wp,所以基地址改变了)

    fgets(s, n[0], stdin);
    v8 = sub_5578E4A20943(n[0]);
    *(_QWORD *)n = sub_5578E4A20996(v14);
    if ( *(_QWORD *)n != v8 )
    {
      v11 = sub_5578E4A209E9(4521);
      if ( s != (char *)v11 )
      {
        v4 = sub_5578E4A212D8((__int64)s, v15, v10, v9, v11, v13);
        if ( v4 != v15 * ((v12 ^ v13) - *(_QWORD *)n) )
          puts("Congratulations! You reversed the reversed reverse!");
      }
    }

发现输入只要输入的地址不等于一个数,然后通过某个判断就行,于是再进到判断前的函数

会看到一个输入参数很多的函数,进去看一下

  v58 = a1 == *a57;
  if ( a2 != a57[1] )
    v58 = 0;
  if ( a3 != a57[2] )
    v58 = 0;
  if ( a4 != a57[3] )
    v58 = 0;
  if ( a5 != a57[4] )
    v58 = 0;
// 以下省略

输入了57个参数,而且就是判断是否相同的,相同就返回1,否则返回0

于是猜测这里就是最终的验证函数

中间经过了一系列动调,确定其它的过程没什么影响,于是在进入函数前下个断点,然后直接去rsp的地址里找比较的数据

最后的内存数据

[stack]:00007FFF9B4402F0 dq '{', 'e', 's', 'r', 'e', 'v', 'e', 'r', '_', 'r', 'e', 'v', 'e', 'r', 's', 'e'
[stack]:00007FFF9B4402F0 dq 'd', '_', 'y', 'o', 'u', 't', 'u', 'b', 'e', '.', 'c', 'o', 'm', '/', 'w', 'a'
[stack]:00007FFF9B4402F0 dq 't', 'c', 'h', '?', 'v', '=', 'I', '8', 'i', 'j', 'b', '4', 'Z', 'e', 'e', '5'
[stack]:00007FFF9B4402F0 dq 'E', '}'

连接起来就是flag了

{esrever_reversed_youtube.com/watch?v=I8ijb4Zee5E}

firmware

一道水题,主要学习一下工控逆向

不难看出,给的附件是squashfs文件,直接进行binwalk

在安装sasquatch时遇到了一些坑,好像必须clone到~/Downloads等文件夹内才行

binwalk之后逛一下目录,能够找到一个叫做 backdoor 的二进制文件

目标是找到连接的ip和端口,进去找一找就能看到

[MR2020]Shit

这题最后的解法很屑(

首先是去花,但花指令和CISCN2021-N的RE2一样,就不细说了

一直尝试反调试,但一直没成功,就用爆破来解了…

char __cdecl sub_DA12F0(const char *a1)
{
  int v2; // [esp+14h] [ebp-14h]
  int i; // [esp+1Ch] [ebp-Ch]
  int v4; // [esp+20h] [ebp-8h]
  int v5; // [esp+20h] [ebp-8h]

  v2 = 0;
  for ( i = 0; i < strlen(a1); i += 4 )
  {
    v4 = __ROR4__(a1[i + 3] | (a1[i + 2] << 8) | (a1[i + 1] << 16) | (a1[i] << 24), dword_DA5034[i / 4]);
    v5 = ((v4 << 16) | (unsigned __int16)~HIWORD(v4)) ^ (1 << dword_DA5034[i / 4]);
    if ( i > 0 )
      v5 ^= v2;
    v2 = v5;
    if ( v5 != dword_DA5018[i / 4] )
      return 0;
  }
  return 1;
}

既然每四位进行一系列位运算,且密钥只有六位,那就爆破吧

from libnum import *

a = [0x8C2C133A, 0x0F74CB3F6, 0x0FEDFA6F2, 0x0AB293E3B, 0x26CF8A2A, 0x88A1F279]

for t in range(len(a)):
    for i in range(32):
        tmp = a[t]
        if t != 0:
            tmp = tmp ^ a[t - 1]
        tmp = tmp ^ (1 << i)
        tmp = ((~tmp & 0xffff) << 16) | (tmp >> 16)
        res = n2s(((tmp >> (0x20 - i)) | (tmp << i)) & 0xffffffff)
        if res[0] > 0x20 and res[0] < 0x7f:
            if res[1] > 0x20 and res[1] < 0x7f:
                if res[2] > 0x20 and res[2] < 0x7f:
                    if res[3] > 0x20 and res[3] < 0x7f:
                        print (res)
    print ()

最后甚至直接上四个 if 了…

爆破结果

b'flag' # 必选
b',ag&'
b"a'f,"
b'gf,!'

b'_2{`'
b'3{`^'
b'{a_3' # 必选
b'`_3z'

b'[a2}'
b'a2y_' # 剩下三个有大括号,排除
b'6}_a'
b'}_e2'

b're_f'
b'e_gs'
b'^fse'
b'fsd_'

b'_4o2'
b'or_t'
b'2_t/'

b'=%st'
b'est}' # 必选
b's4=e'
b't=e3'

中间根据前后单词拼接一下就行了

  • Shit这道题还是要看一下别人的WP,学习一下正确的思路

[SUCTF2018]HelloPython

uncompyle6

(lambda __target: [ (lambda __target: [ [ __this() for __g['n'] in [__operator.isub(__g['n'], 1)] ][0] for __target.value in [__operator.iadd(__target.value, (y.value << 4) + k[2] ^ y.value + x.value ^ (y.value >> 5) + k[3])] ][0])(z) for __target.value in [__operator.iadd(__target.value, (z.value << 4) + k[0] ^ z.value + x.value ^ (z.value >> 5) + k[1])] ][0])(y)

很明显是tea

void encrypt (uint32_t* v, uint32_t* k) {  
    uint32_t v0=v[0], v1=v[1], sum=0, i;           /* set up */  
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */  
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */  
    for (i=0; i < 32; i++) {                       /* basic cycle start */  
        sum += delta;  
        v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);  
        v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);  
    }                                              /* end cycle */  
    v[0]=v0; v[1]=v1;  
}

对比一下,z是v[1],x是sum,y是v[0],或者看下面这段

for __g['x'] in [c_uint32(0)] ][0] for __g['z'] in [c_uint32(v[1])] ][0] for __g['y'] in [c_uint32(v[0])]

delta常数

for __g['u'] in [2654435769]

密钥常数

for __g['k'] in [[3735928559, 590558003, 19088743, 4275878552]]

到题目描述里找到密文 f1f5d29b6e4414ec(这还得自己去github找,离谱)

解密

#include <stdio.h>  
#include <stdint.h>  
  
//加密函数  
void encrypt (uint32_t* v, uint32_t* k) {  
    uint32_t v0=v[0], v1=v[1], sum=0, i;           /* set up */  
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */  
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */  
    for (i=0; i < 32; i++) {                       /* basic cycle start */  
        sum += delta;  
        v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);  
        v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);  
    }                                              /* end cycle */  
    v[0]=v0; v[1]=v1;  
}  
//解密函数  
void decrypt (uint32_t* v, uint32_t* k) {  
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */  
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */  
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */  
    for (i=0; i<32; i++) {                         /* basic cycle start */  
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);  
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);  
        sum -= delta;  
    }                                              /* end cycle */  
    v[0]=v0; v[1]=v1;  
}  
  
int main()  
{  
    uint32_t v[2]={0xf1f5d29b, 0x6e4414ec},k[4]={3735928559, 590558003, 19088743, 4275878552};  
    // v为要加密的数据是两个32位无符号整数  
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位  
    // printf("加密前原始数据:%u %u\n",v[0],v[1]);  
    // encrypt(v, k);  
    // printf("加密后的数据:%u %u\n",v[0],v[1]);  
    decrypt(v, k);  
    printf("解密后的数据:%x %x\n",v[0],v[1]);  
    return 0;  
}  

[FBCTF]go_get_the_flag

没想到能在第五页见到memequal的题,真正的baby

[Zer0pts2020]QR Puzzle

QR文件是25*25的字符串,每一位都是字符0或1

key文件每一行格式为 a#(b,c),最后存储到链表中,末尾在前,具体结构为 int b, int c, int a, 0, *next

从加密函数来看,应该是一个vm

简单整理一下

void __fastcall sub_400BD0(__int64 a1, int *a2)
{
  int v2; // er8
  int v3; // edx
  _QWORD *v4; // r9
  _QWORD *v5; // rcx
  int v6; // er9
  __int64 v7; // rax
  __int64 v8; // rcx

  while ( a2 ) {
    x = a2[2];
    y = a2[0];
    z = a2[1];
    if ( x == 1 ) {
      v2 = z;
      v3 = y + 1;
      goto LABEL_4;
    }
    if ( x == 0 ) {
      v2 = z;
      v3 = y - 1;
      goto LABEL_4;
    }
    if ( x == 3 ) {
      v2 = z + 1;
      v3 = y;
      goto LABEL_4;
    }
    if ( x == 2 ) {
      v2 = z - 1;
      v3 = y;
    }
LABEL_4:
    v4 = &a1[z];
    v5 = &a1[v2];
    *(_BYTE *)(v7 + *v4) += *(_BYTE *)(*v5 + v3);
    *(_BYTE *)(v3 + *v5) = *(_BYTE *)(*v4 + v7) - *(_BYTE *)(v3 + *v5);
    *(_BYTE *)(*v4 + v7) -= *(_BYTE *)(*v5 + v3); // 经典swap
    a2 = (int *)*((_QWORD *)a2 + 2);              // a2 = a2->next
  }
}

显然加密就是和周围某个位置交换一下

解密和加密是对称的,直接把key文件反转过来,就是解密了

接下来需要把01串变成图片

from PIL import Image

def black_block(image, x, y):
    for i in range(5):
            for j in range(5):
                    image.putpixel((x + i, y + j), (0, 0, 0))

im = Image.new('RGB', (125, 125), "#FFFFFF")

flag = [
    '1111111001000101001111111',
    '1000001011001001001000001',
    '1011101001110011101011101',
    '1011101001100010101011101',
    '1011101011000111001011101',
    '1000001001110111101000001',
    '1111111010101010101111111',
    '0000000000101101100000000',
    '1010101000001110000010010',
    '0011100010000110101001001',
    '1001001100011110111010011',
    '1110110110001111000101000',
    '0101001011011100011101011',
    '0101100101111010101001011',
    '1001011011011000000100111',
    '0101010010001110011110011',
    '1001101001110010111111000',
    '0000000011110000100011001',
    '1111111001100101101010111',
    '1000001001010001100010000',
    '1011101011101000111111011',
    '1011101000111101000010000',
    '1011101010111011010110101',
    '1000001001001111111010010',
    '1111111011110011100011011'
]

for i in range(len(flag)):
    for j in range(len(flag[0])):
            if flag[i][j] == '1':
                    black_block(im, i * 5, j * 5)

im.show()

扫描二维码拿flag

[XMAN2018排位赛]easyvm

vm题,上来先把字节翻译成汇编格式

vm_code = [
    0x05, 0x01, 0x0B, 0x13, 0x03, 0x03, 0x13, 0x00, 0x00, 0x13, 
    0x04, 0x04, 0x28, 0x0C, 0x00, 0x33, 0x14, 0x00, 0x20, 0x05, 
    0x09, 0x01, 0x11, 0x09, 0x00, 0x0B, 0x0A, 0x09, 0x01, 0x04, 
    0x0A, 0x1B, 0x05, 0x04, 0x0C, 0x03, 0x01, 0x24, 0x03, 0x20, 
    0x28, 0x13, 0x00, 0x00, 0x07, 0x08, 0x05, 0x0E, 0x08, 0xE0, 
    0x07, 0x02, 0x08, 0x09, 0x0A, 0x02, 0x01, 0x00, 0x0A, 0x18, 
    0x00, 0xE0, 0x1E, 0x00, 0x05, 0x01, 0x04, 0x00, 0x13, 0x03, 
    0x03, 0x28, 0x09, 0x0A, 0x02, 0x01, 0x00, 0x0A, 0x18, 0x00, 
    0x1F, 0x20, 0x00, 0x03, 0x1B, 0x05, 0x00, 0x07, 0x08, 0x05, 
    0x0E, 0x08, 0xE0, 0x07, 0x02, 0x08, 0x09, 0x0A, 0x02, 0x01, 
    0x00, 0x0A, 0x18, 0x00, 0xE0, 0x1E, 0x00, 0x05, 0x1D, 0x05, 
    0x0A, 0x0D, 0x0A, 0x00, 0x1B, 0x05, 0x0A, 0x0C, 0x03, 0x01, 
    0x24, 0x03, 0x1F, 0x28, 0x09, 0x0A, 0x02, 0x01, 0x00, 0x0A, 
    0x18, 0x00, 0x1F, 0x20, 0x00, 0x03, 0x0D, 0x00, 0x04, 0x1B, 
    0x05, 0x00, 0x13, 0x03, 0x03, 0x03, 0x04, 0x0D, 0x28, 0x07, 
    0x08, 0x05, 0x0E, 0x08, 0xE0, 0x07, 0x02, 0x08, 0x09, 0x0A, 
    0x02, 0x01, 0x00, 0x0A, 0x1B, 0x05, 0x00, 0x01, 0x00, 0x04, 
    0x0D, 0x00, 0x03, 0x1D, 0x05, 0x0A, 0x13, 0x0A, 0x00, 0x1B, 
    0x05, 0x0A, 0x22, 0x04, 0x08, 0x0C, 0x03, 0x01, 0x24, 0x03, 
    0x20, 0x28, 0x13, 0x03, 0x03, 0x13, 0x04, 0x04, 0x05, 0x01, 
    0x0C, 0x28, 0x05, 0x09, 0x01, 0x11, 0x09, 0x03, 0x0B, 0x0A, 
    0x09, 0x01, 0x00, 0x0A, 0x1B, 0x05, 0x00, 0x07, 0x08, 0x05, 
    0x0E, 0x08, 0xDF, 0x09, 0x0A, 0x08, 0x1D, 0x05, 0x00, 0x1B, 
    0x05, 0x00, 0x27, 0x00, 0x0A, 0x17, 0x04, 0x07, 0x0C, 0x03, 
    0x01, 0x24, 0x03, 0x20, 0x28, 0x2A, 0x00, 0x00
]

index = 0
length = len(vm_code)
inloop = 0
while index < length:
    v22 = vm_code[index]
    v6 = vm_code[index + 1]
    v5 = vm_code[index + 2]
    v21 = vm_code[index] & 0xFE
    v20 = vm_code[index] & 1
    if v21 == 0:
        if v20 == 1:
            print (f'_{index}: mov v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: mov v23[{v6}], {v5}')
        index += 2
    elif v21 == 2:
        if v20 == 1:
            print (f'_{index}: mov32 v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: mov32 v23[{v6}], {v5}')
        index += 2
    elif v21 == 4:
        if v20 == 1:
            print (f'_{index}: lea_ch v23[{v6}], v23[{v5}]')
            index += 2
    elif v21 == 6:
        if v20 == 1:
            print (f'_{index}: lea_int v23[{v6}], v23[{v5}]')
        index += 2
    elif v21 == 8:
        if v20 == 1:
            print (f'_{index}: ldr_int v23[{v6}], v23[{v5}]')
        index += 2
    elif v21 == 0xA:
        if v20 == 1:
            print (f'_{index}: ldr_ch v23[{v6}], v23[{v5}]')
        index += 2
    elif v21 == 0xC:
        if v20 == 1:
            print (f'_{index}: add v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: add v23[{v6}], {v5}')
        index += 2
    elif v21 == 0xE:
        if v20 == 1:
            print (f'_{index}: add_pint v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: add_pint v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x10:
        if v20 == 1:
            print (f'_{index}: add_pch v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: add_pch v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x12:
        if v20 == 1:
            print (f'_{index}: my_xor v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: my_xor v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x14:
        if v20 == 0:
            print (f'_{index}: mod v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x16:
        if v20 == 1:
            print (f'_{index}: my_or v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: my_or v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x18:
        if v20 == 1:
            print (f'_{index}: my_and v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: my_and v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x1A:
        if v20 == 1:
            print (f'_{index}: push v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: push v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x1C:
        if v20 == 1:
            print (f'_{index}: pop v23[{v6}], v23[{v5}]')
        index += 2
    elif v21 == 0x1E:
        if v20 == 1:
            print (f'_{index}: shr v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: shr v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x20:
        if v20 == 1:
            print (f'_{index}: shl v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: shl v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x22:
        if v20 == 1:
            print (f'_{index}: ror v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: ror v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x24:
        if v20 == 1:
            print (f'_{index}: cmpl v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: cmpl v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x26:
        if v20 == 1:
            print (f'_{index}: cmpeq v23[{v6}], v23[{v5}]')
        if v20 == 0:
            print (f'_{index}: cmpeq v23[{v6}], {v5}')
        index += 2
    elif v21 == 0x28:
        if inloop == 0:
            print (f'\n_{index}: start_loop')
            inloop = 1
        elif inloop == 1:
            print (f'_{index}: end_loop\n')
            inloop = 0
    elif v21 == 0x2A:
        print (f'_{index}: judge')
        break
    index += 1

转换结果

_0: lea_ch v23[1], v23[11]
_3: my_xor v23[3], v23[3]
_6: my_xor v23[0], v23[0]
_9: my_xor v23[4], v23[4]

_12: start_loop
_13: add v23[0], 51
_16: mod v23[0], 32
_19: lea_ch v23[9], v23[1]
_22: add_pch v23[9], v23[0]
_25: ldr_ch v23[10], v23[9]
_28: mov v23[4], v23[10]
_31: push v23[5], v23[4]
_34: add v23[3], 1
_37: cmpl v23[3], 32
_40: end_loop

_41: my_xor v23[0], v23[0]
_44: lea_int v23[8], v23[5]
_47: add_pint v23[8], 224
_50: lea_int v23[2], v23[8]
_53: ldr_int v23[10], v23[2]
_56: mov v23[0], v23[10]
_59: my_and v23[0], 224
_62: shr v23[0], 5
_65: mov v23[4], v23[0]
_68: my_xor v23[3], v23[3]

_71: start_loop
_72: ldr_int v23[10], v23[2]
_75: mov v23[0], v23[10]
_78: my_and v23[0], 31
_81: shl v23[0], 3
_84: push v23[5], v23[0]
_87: lea_int v23[8], v23[5]
_90: add_pint v23[8], 224
_93: lea_int v23[2], v23[8]
_96: ldr_int v23[10], v23[2]
_99: mov v23[0], v23[10]
_102: my_and v23[0], 224
_105: shr v23[0], 5
_108: pop v23[5], v23[10]
_111: add v23[10], v23[0]
_114: push v23[5], v23[10]
_117: add v23[3], 1
_120: cmpl v23[3], 31
_123: end_loop

_124: ldr_int v23[10], v23[2]
_127: mov v23[0], v23[10]
_130: my_and v23[0], 31
_133: shl v23[0], 3
_136: add v23[0], v23[4]
_139: push v23[5], v23[0]
_142: my_xor v23[3], v23[3]
_145: mov32 v23[4], v23[13]

_148: start_loop
_149: lea_int v23[8], v23[5]
_152: add_pint v23[8], 224
_155: lea_int v23[2], v23[8]
_158: ldr_int v23[10], v23[2]
_161: mov v23[0], v23[10]
_164: push v23[5], v23[0]
_167: mov v23[0], v23[4]
_170: add v23[0], v23[3]
_173: pop v23[5], v23[10]
_176: my_xor v23[10], v23[0]
_179: push v23[5], v23[10]
_182: ror v23[4], 8
_185: add v23[3], 1
_188: cmpl v23[3], 32
_191: end_loop

_192: my_xor v23[3], v23[3]
_195: my_xor v23[4], v23[4]
_198: lea_ch v23[1], v23[12]

_201: start_loop
_202: lea_ch v23[9], v23[1]
_205: add_pch v23[9], v23[3]
_208: ldr_ch v23[10], v23[9]
_211: mov v23[0], v23[10]
_214: push v23[5], v23[0]
_217: lea_int v23[8], v23[5]
_220: add_pint v23[8], 223
_223: ldr_int v23[10], v23[8]
_226: pop v23[5], v23[0]
_229: push v23[5], v23[0]
_232: cmpeq v23[0], v23[10]
_235: my_or v23[4], v23[7]
_238: add v23[3], 1
_241: cmpl v23[3], 32
_244: end_loop

_245: judge

因为是Mach-O文件,不会动调,只能看静态了(成功被指针恶心到了,算法全靠猜)

第一个循环就是进行了一个顺序上的转换(类似栅栏吧)

第二个循环看到有先右移5bit,再左移3bit,一开始猜测可能是字节内部转换,后来发现在循环的前也有个右移,循环后也有个左移,代码几乎都一样,猜测是所有字节一起进行位移

第三个循环注意到有个 ror 的循环右移,然后还有异或,就是每次异或一个字节

最后写一个解密,从文件里dump出密文和key

cipher = [
    0x75, 0x85, 0xD1, 0x39, 0x0B, 0x29, 0xCD, 0x77, 0x6D, 0x9F, 
    0x73, 0x23, 0x61, 0x8B, 0x4D, 0x45, 0x9D, 0x8F, 0x5B, 0x11, 
    0xC1, 0xC9, 0xE5, 0xCF, 0x45, 0xE5, 0xB1, 0xB3, 0x41, 0xD9, 
    0xCF, 0xCF
]

key = [0xDE, 0xAD, 0xBE, 0xEF]

s = 0

for i in range(32):
    cipher[i] ^= key[i % 4] + i
    cipher[i] &= 0xFF
    s <<= 8
    s += cipher[i]

s <<= 5
s += (s >> (len(bin(s)[2:]) - 5))
s &= ((1 << (32 * 8)) - 1)

from libnum import *

i = 35
flag = [0 for _ in range(32)]
for _ in range(32):
    i += -5
    i %= 32
    print (chr(n2s(s)[i]), end = '')

print ()

VM题真是体力活

[RCTF2019]babyre1

这题其实出的挺好,就是flag的校验差一字节没写好,可惜了

先要输入flag,并长度不能超过 0x10

  __printf_chk(1LL, "Input right flag you can got 'Bingo!' :");
  __isoc99_scanf("%31s", v11);
  v3 = &v11[strlen(v11)];
  if ( (unsigned __int64)(v3 - v11) > 0x10 )
  {
    puts("input is too long!");
  }

然后在else里进行的第一个函数中,将16位输入(按照十六进制)压缩成了8个字节,这里还没有要求大小写

中间经过的加解密函数先略过,后面的验证是需要输出一个 Bingo!,要求CRC16的校验结果为0x69E2,然后就会对运算结果再异或 0x17 并输出,程序如下

    if ( v4
      && (v5 = sub_180(ptr, v4, &key_202010, 16, &a5), (v6 = v5) != 0LL)
      && a5 > 0
      && CRC16_3D0(v5, a5) == 0x69E2 )
    {
      for ( i = 0LL; a5 > (int)i; ++i )
        v6[i] ^= 0x17u;
      puts(v6);
      if ( ptr )
        free(ptr);
      free(v6);
    }

在知道运算结果后,看一下中间的运算,核心逻辑为

        xxtea_CE0((int *)v8, -(v10 >> 2), a3);
        v11 = v8[a2 - 1];
        v8[a2] = 0;
        *a5 = a2;
        if ( a2 > v11 && v11 <= 4 )
        {
          v13 = a2 - v11;
          *a5 = v13;
          v8[v13] = 0;
          return (char *)v8;
        }

就是一个xxtea的程序(其中包括了加密和解密,特征很明显,就不展示了),然后是根据最后一个字节进行字符串的截断

爆破了一下CRC,发现前六个字节正好满足,于是不知道咋办了,查了一下发现后来出题人提供了一个md5,那就写个解密程序然后爆破就行了

[INSHack2017]proprietary-cctv-software

这题用uncompyle6能还原出来源码,是一个PyQt的代码,输入验证部分为

    def btn_ok_clicked(self):
        s = ''
        for le in self.le_parts:
            s += le.text()
            s += '-'

        s = s[:-1]
        if self.activator.activate(s.upper()):
            self.c.ok.emit()
        else:
            self.c.ko.emit()
        self.close()

以及

class Activator(object):
    CHARSET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'

    def __init__(self):
        super(Activator, self).__init__()
        self.z = 36
        self.checksum = [30, 24, 18, 12, 6, 0]

    def block(self, b, mod):
        print_dbg('call: block(self, b=<%s>, mod=%d)' % (b, mod))
        if len(b) != 6:
            print_dbg('err: incorrect block length (%d)' % len(b))
            return
        s = 0
        for k in range(0, len(b)):
            l = b[k]
            if l not in Activator.CHARSET:
                print_dbg('err: input not found in charset (%s)' % l)
                return
            v = abs(Activator.CHARSET.index(l) - (k + 1))
            s += v
            print_dbg('current l is: %s' % l)
            print_dbg('current k is: %d' % k)
            print_dbg('current value is: %d' % v)
            print_dbg('current sum is: %d' % s)

        return s % mod

    def activate(self, s):
        print_dbg('call: activate(self, s=<%s>)' % s)
        blocks = s.split('-')
        blocks_sz = len(blocks)
        if blocks_sz != 6:
            print_dbg('err: incorrect number of blocks (%d)' % blocks_sz)
            return False
        for k in range(0, blocks_sz):
            self.z = self.block(blocks[k], self.z)
            print_dbg('dbg: new z is: %d' % self.z)
            if self.z is None:
                print_dbg('err: block function returned error')
                return False
            if self.z != self.checksum[k]:
                print_dbg('err: incorrect checksum (z=%d tested against checksum[%d]=%d)' % (self.z, k, self.checksum[k]))
                return False

        return True

一个方法是逆向这一部分,然后运行程序,应该就能拿到flag

但懒得配环境了,所以又找了一下flag生成函数

class ActivatedWidget(QWidget):
    __doc__ = 'docstring for ActivatedWidget'

    def __init__(self):
        super(ActivatedWidget, self).__init__()
        self.lab_result = None
        self.yek = [
         5, 202, 234, 95,
         76, 173, 96, 10,
         232, 7, 146, 79,
         111, 147, 145, 13]
        self.vei = [
         175, 161, 61, 70,
         144, 218, 0, 50,
         73, 173, 240, 202,
         184, 17, 148, 2]
        self.cne = [
         253, 14, 187, 117,
         252, 19, 15, 86,
         196, 138, 67, 165,
         142, 237, 112, 47,
         154, 189, 33, 75,
         195, 205, 10, 56,
         3, 230, 180, 147,
         134, 27, 143, 15,
         250, 19, 235, 96,
         231, 5, 74, 83,
         136, 149, 79, 170,
         136, 252, 113, 112,
         223, 248, 33, 119,
         206, 218, 79, 121,
         9, 225, 253, 156,
         136, 26, 146, 93,
         188, 94, 170, 79,
         184, 87, 102, 61,
         178, 167, 20, 231,
         132, 253, 106, 38,
         141, 224, 112, 98,
         171, 153, 50, 89,
         5, 194, 181, 247,
         137, 23, 139, 31,
         251, 89, 169, 89,
         198, 127, 97, 10,
         170, 246, 105, 197,
         226, 128, 30, 22]
        self.init_ui()

    def finalize(self):
        clear = ''
        buf = self.cne
        key = self.yek
        iv = self.vei
        buf_sz = len(buf)
        bsize = 16
        for i in range(0, int(buf_sz / bsize)):
            for j in range(0, bsize):
                c = buf[(i * bsize + j)] ^ key[j] ^ iv[j]
                iv[j] = buf[(i * bsize + j)]
                buf[i * bsize + j] = c

        i = buf[(buf_sz - 1)]
        for j in range(0, i):
            buf[buf_sz - 1 - j] = 0

        for i in range(0, buf_sz):
            if buf[i] == 0:
                break
            clear += chr(buf[i])

        return clear

手动将这一段提取出来,然后修改一下,将 return 改成 print ,也能拿到flag

简要记录pycdc的bug

ROT_TWO指令未成功还原

好像是蓝帽杯决赛的时候遇到的问题吧?当时用pycdas手动解的,后来修改了一下pyc文件前几个字节的混淆,用pycdc跑完后发现的问题(可能是混淆没去干净,只还原出了前三个函数,不过正好发现了这个bug)

手动还原的为:

def gen_prime(n_bits):
    res = gen_num(n_bits)
    while not g.is_prime(res):
        b = 1
        while b != 0:
            res, b = res ^ b, (res & b) << 1
    return res

然后用pycdc还原的为:

def gen_prime(n_bits):
    res = gen_num(n_bits)
    while not g.is_prime(res):
        b = 1
        while b != 0:
            res = res ^ b
            b = (res & b) << 1
    return res

附上pycdas结果

        [Code]
            File Name: /somewhere/encrypt.py
            Object Name: gen_prime
            Arg Count: 1
            KW Only Arg Count: 0
            Locals: 3
            Stack Size: 3
            Flags: 0x00000043 (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)
            [Names]
                'gen_num'
                'g'
                'is_prime'
            [Var Names]
                'n_bits'
                'res'
                'b'
            [Free Vars]
            [Cell Vars]
            [Constants]
                None
                1
                0
            [Disassembly]
                0       LOAD_GLOBAL             0: gen_num
                2       LOAD_FAST               0: n_bits
                4       CALL_FUNCTION           1
                6       STORE_FAST              1: res
                8       SETUP_LOOP              54 (to 64)
                10      LOAD_GLOBAL             1: g
                12      LOAD_METHOD             2: is_prime
                14      LOAD_FAST               1: res
                16      CALL_METHOD             1
                18      POP_JUMP_IF_TRUE        62
                20      LOAD_CONST              1: 1
                22      STORE_FAST              2: b
                24      SETUP_LOOP              34 (to 60)
                26      LOAD_FAST               2: b
                28      LOAD_CONST              2: 0
                30      COMPARE_OP              3 (!=)
                32      POP_JUMP_IF_FALSE       58
                34      LOAD_FAST               1: res
                36      LOAD_FAST               2: b
                38      BINARY_XOR              
                40      LOAD_FAST               1: res
                42      LOAD_FAST               2: b
                44      BINARY_AND              
                46      LOAD_CONST              1: 1
                48      BINARY_LSHIFT           
                50      ROT_TWO                 
                52      STORE_FAST              1: res
                54      STORE_FAST              2: b
                56      JUMP_ABSOLUTE           26
                58      POP_BLOCK               
                60      JUMP_ABSOLUTE           10
                62      POP_BLOCK               
                64      LOAD_FAST               1: res
                66      RETURN_VALUE            
        'gen_prime'

明显有个 ROT_TWO

后来队友手写了一个demo测试了一下

手写的为

a = a ^ b
b = a | b

a, b = a ^ b, a | b

然后pycdc结果都是

a = a ^ b
b = a | b

pycdas结果则是一个有 ROT_TWO,一个没有,是正确的

if判断后接for循环时出现无限嵌套

在做INSHACK2017那道题的时候,一开始电脑里没装uncompyle6,于是打算拿pycdc解,但运行了一下,发现直接生成了一个2G的文件,要不是SegmentFault了估计还能生成,用pycdas解了一下,感觉没什么问题

pycdc卡住的部分:

    def activate(self, s):
        print_dbg('call: activate(self, s=<%s>)' % s)
        blocks = s.split('-')
        blocks_sz = len(blocks)
        if blocks_sz != 6:
            print_dbg('err: incorrect number of blocks (%d)' % blocks_sz)
            return False
        :
            print_dbg('call: activate(self, s=<%s>)' % s)
            blocks = s.split('-')
            blocks_sz = len(blocks)
            if blocks_sz != 6:
                print_dbg('err: incorrect number of blocks (%d)' % blocks_sz)
                return False
            :
                print_dbg('call: activate(self, s=<%s>)' % s)
                blocks = s.split('-')
                blocks_sz = len(blocks)
                if blocks_sz != 6:
                    print_dbg('err: incorrect number of blocks (%d)' % blocks_sz)
                    return False
                :
                    print_dbg('call: activate(self, s=<%s>)' % s)
                    blocks = s.split('-')
                    blocks_sz = len(blocks)
                    if blocks_sz != 6:
                        print_dbg('err: incorrect number of blocks (%d)' % blocks_sz)
                        return False
                    :
                    # 后面就是无限嵌套了

uncompyle6结果

    def activate(self, s):
        print_dbg('call: activate(self, s=<%s>)' % s)
        blocks = s.split('-')
        blocks_sz = len(blocks)
        if blocks_sz != 6:
            print_dbg('err: incorrect number of blocks (%d)' % blocks_sz)
            return False
        for k in range(0, blocks_sz):
            self.z = self.block(blocks[k], self.z)
            print_dbg('dbg: new z is: %d' % self.z)
            if self.z is None:
                print_dbg('err: block function returned error')
                return False
            if self.z != self.checksum[k]:
                print_dbg('err: incorrect checksum (z=%d tested against checksum[%d]=%d)' % (self.z, k, self.checksum[k]))
                return False

        return True

pycdas结果

                [Code]
                    File Name: src/standalone/cctv_manager_standalone.py
                    Object Name: activate
                    Arg Count: 2
                    KW Only Arg Count: 0
                    Locals: 5
                    Stack Size: 7
                    Flags: 0x00000043 (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)
                    [Names]
                        'print_dbg'
                        'split'
                        'len'
                        'range'
                        'block'
                        'z'
                        'checksum'
                    [Var Names]
                        'self'
                        's'
                        'blocks'
                        'blocks_sz'
                        'k'
                    [Free Vars]
                    [Cell Vars]
                    [Constants]
                        None
                        'call: activate(self, s=<%s>)'
                        '-'
                        6
                        'err: incorrect number of blocks (%d)'
                        False
                        0
                        'dbg: new z is: %d'
                        'err: block function returned error'
                        'err: incorrect checksum (z=%d tested against checksum[%d]=%d)'
                        True
                    [Disassembly]
                        0       LOAD_GLOBAL             0: print_dbg
                        3       LOAD_CONST              1: 'call: activate(self, s=<%s>)'
                        6       LOAD_FAST               1: s
                        9       BINARY_MODULO           
                        10      CALL_FUNCTION           1
                        13      POP_TOP                 
                        14      LOAD_FAST               1: s
                        17      LOAD_ATTR               1: split
                        20      LOAD_CONST              2: '-'
                        23      CALL_FUNCTION           1
                        26      STORE_FAST              2: blocks
                        29      LOAD_GLOBAL             2: len
                        32      LOAD_FAST               2: blocks
                        35      CALL_FUNCTION           1
                        38      STORE_FAST              3: blocks_sz
                        41      LOAD_FAST               3: blocks_sz
                        44      LOAD_CONST              3: 6
                        47      COMPARE_OP              3 (!=)
                        50      POP_JUMP_IF_FALSE       71
                        53      LOAD_GLOBAL             0: print_dbg
                        56      LOAD_CONST              4: 'err: incorrect number of blocks (%d)'
                        59      LOAD_FAST               3: blocks_sz
                        62      BINARY_MODULO           
                        63      CALL_FUNCTION           1
                        66      POP_TOP                 
                        67      LOAD_CONST              5: False
                        70      RETURN_VALUE            
                        71      SETUP_LOOP              156 (to 230)
                        74      LOAD_GLOBAL             3: range
                        77      LOAD_CONST              6: 0
                        80      LOAD_FAST               3: blocks_sz
                        83      CALL_FUNCTION           2
                        86      GET_ITER                
                        87      FOR_ITER                139 (to 229)
                        90      STORE_FAST              4: k
                        93      LOAD_FAST               0: self
                        96      LOAD_ATTR               4: block
                        99      LOAD_FAST               2: blocks
                        102     LOAD_FAST               4: k
                        105     BINARY_SUBSCR           
                        106     LOAD_FAST               0: self
                        109     LOAD_ATTR               5: z
                        112     CALL_FUNCTION           2
                        115     LOAD_FAST               0: self
                        118     STORE_ATTR              5: z
                        121     LOAD_GLOBAL             0: print_dbg
                        124     LOAD_CONST              7: 'dbg: new z is: %d'
                        127     LOAD_FAST               0: self
                        130     LOAD_ATTR               5: z
                        133     BINARY_MODULO           
                        134     CALL_FUNCTION           1
                        137     POP_TOP                 
                        138     LOAD_FAST               0: self
                        141     LOAD_ATTR               5: z
                        144     LOAD_CONST              0: None
                        147     COMPARE_OP              8 (is)
                        150     POP_JUMP_IF_FALSE       167
                        153     LOAD_GLOBAL             0: print_dbg
                        156     LOAD_CONST              8: 'err: block function returned error'
                        159     CALL_FUNCTION           1
                        162     POP_TOP                 
                        163     LOAD_CONST              5: False
                        166     RETURN_VALUE            
                        167     LOAD_FAST               0: self
                        170     LOAD_ATTR               5: z
                        173     LOAD_FAST               0: self
                        176     LOAD_ATTR               6: checksum
                        179     LOAD_FAST               4: k
                        182     BINARY_SUBSCR           
                        183     COMPARE_OP              3 (!=)
                        186     POP_JUMP_IF_FALSE       87
                        189     LOAD_GLOBAL             0: print_dbg
                        192     LOAD_CONST              9: 'err: incorrect checksum (z=%d tested against checksum[%d]=%d)'
                        195     LOAD_FAST               0: self
                        198     LOAD_ATTR               5: z
                        201     LOAD_FAST               4: k
                        204     LOAD_FAST               0: self
                        207     LOAD_ATTR               6: checksum
                        210     LOAD_FAST               4: k
                        213     BINARY_SUBSCR           
                        214     BUILD_TUPLE             3
                        217     BINARY_MODULO           
                        218     CALL_FUNCTION           1
                        221     POP_TOP                 
                        222     LOAD_CONST              5: False
                        225     RETURN_VALUE            
                        226     JUMP_ABSOLUTE           87
                        229     POP_BLOCK               
                        230     LOAD_CONST              10: True
                        233     RETURN_VALUE            
                'Activator.activate'

也没看出来什么问题

Built with Hugo
Theme Stack designed by Jimmy