• Home
  • About
    • back
    • Rhy7hm photo

      Rhy7hm

      天天被计算机教做人

    • Learn More
    • Email
  • Posts
    • back
    • All Posts
    • All Tags
  • Projects

ReReReeeeeeee

19 Nov 2018

Reading time ~2 minutes

ReReReeeeeeee

$从湖湘杯说起$

让我们来一起学$湖湘杯$的参赛选手叫,一起:

下面是某道密(ni)码(xiang)题的WP

Crypto 200

题目翻译成python如下:

from Crypto.Cipher import AES

key = '1b2e3546586e72869ba7b5c8d9efff0c'.decode('hex')

cipher = AES.new(key, AES.MODE_ECB)

en_flag = '8aeb45c62003ba52e46c9600b3699b8c30386334623434393136633963356136'

(cipher.encrypt(flag[0:16]) + flag[16:]).encode('hex')= en_flag

#求flag

AES部分可以使用:PEID的Krypto ANALyzer插件

可以看到在.rdata:000000014001AC50有AES的S盒:

63h, 7Ch, 77h, 7Bh, 0F2h, 6Bh, 6Fh, 0C5h, 30h, 1, 67h ……

该部分的数据被sub_1400012A0((unsigned __int8 *)&Buf, (__int64)&String1);调用,所以显然sub_1400012A0是AES加密

其中的Buf是用户的输入,Sting1是秘钥key

进入sub_140001000函数可以轻易看到秘钥存放在.data:000000014001DA40处

但是经过动态调试可以发现,该函数只会对buf中的前16bytes进行aes加密,后面的不变。


然后是hex部分

ida伪代码:

  v4 = &Buf;
  v5 = 32i64;
  v6 = &String1;
  do
  {
    sub_140001550((__int64)v6, (__int64)"%.2x", *(unsigned __int8 *)v4, v3);
    //sprintf(Sting1,"%.2x",Buf);
    v6 += 2;
    v4 = (__int64 *)((char *)v4 + 1);
    --v5;
  }
  while ( v5 );

%.2x那么明显,所以为什么不能一眼看出来是sprintf呢,为什么呢,为什么呢

C 库函数 int sprintf(char *str, const char *format, …) :发送格式化输出到 str 所指向的字符串。 C 库函数 int vsprintf(char *str, const char *format, va_list arg): 使用参数列表发送格式化输出到字符串。

更何况,sub_140001550点进去是这样的

__int64 __fastcall sub_140001550(__int64 a1, __int64 a2, __int64 a3, __int64 a4)
{
  __int64 v4; // rbx
  _BYTE *v5; // rdi
  _QWORD *v6; // rax
  __int64 result; // rax
  __int64 v8; // [rsp+60h] [rbp+18h]
  __int64 v9; // [rsp+68h] [rbp+20h]

  v8 = a3;
  v9 = a4;
  v4 = a2;
  v5 = (_BYTE *)a1;
  v6 = (_QWORD *)sub_1400014E0();
  result = _stdio_common_vsprintf((struct __crt_locale_pointers *)(*v6 | 1i64), v5, 0xFFFFFFFFFFFFFFFFui64, v4, 0i64);
  if ( (signed int)result < 0 )
    result = 0xFFFFFFFFi64;
  return result;
}

我不知道怎么回事一开始就把_stdio_common_vsprintf的函数名改了然后在里面逆了一整天,美滋滋

所以上面的while循环是把Buf里的内容(32Bytes)赋值给String1,其中Buf里的就是AES(flag[0:16],key) + flag[16:]

最后是

  if ( lstrcmpA(&String1, "8aeb45c62003ba52e46c9600b3699b8c30386334623434393136633963356136") )
    exit(0);
  sub_1400014F0("successful!\nplease entry any key exit...", v7, v8);

所以AES(flag[0:16],key) + flag[16:]跟它给的字符串一致就是flag了

解题代码还要吗:

from Crypto.Cipher import AES

key = '1b2e3546586e72869ba7b5c8d9efff0c'.decode('hex')

cipher = AES.new(key, AES.MODE_ECB)

en_flag = '8aeb45c62003ba52e46c9600b3699b8c30386334623434393136633963356136'
#这个每题都不同的好像

print cipher.decrypt(en_flag.decode('hex'))[0:16] + en_flag.decode('hex')[16:]

Tips

tips1:IDA反汇编的结果,不但参数可能不对,参数数量也可能不对

如:

sub_140001550((__int64)v6, (__int64)"%.2x", *(unsigned __int8 *)v4, v3);

汇编代码是:

.text:0000000140001660 loc_140001660:                          ; CODE XREF: main+CF↓j
.text:0000000140001660                 movzx   r8d, byte ptr [rdi]
.text:0000000140001664                 lea     rdx, a2x        ; "%.2x"
.text:000000014000166B                 mov     rcx, rbx        ; __int64
.text:000000014000166E                 call    sub_140001550

所以其实只有三个参数

tips2:windows平台下的动态调试,32位的可以用ollydbg,64位可以用x64dbg

tips3:对于整数和指针类型参数, x64使用6个寄存器传递前6个参数:edi,rsi,rdx,rcx,r8,r9。从第七个开始通过栈传递。说得不对的话找这里


进入正题

re现阶段总结

函数和算法

strlen

0x80808080

0x01010101

参考:

https://github.com/lattera/glibc/blob/master/string/strlen.c

http://www.stdlib.net/~colmmacc/strlen.c.html

https://stackoverflow.com/questions/20021066/how-the-glibc-strlen-implementation-works


AES

可参考:$S-BOX$

0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F(encode)

或

0x52,0x09,0x6A,0xD5,0x30,0x36(decode)

参考:

https://github.com/B-Con/crypto-algorithms/blob/master/aes.c


DES

14, 4, 13, 1, 2, 15, 11, 8 或 ‘0xe’, ‘0x4’, ‘0xd’, ‘0x1’, ‘0x2’, ‘0xf’, ‘0xb’, ‘0x8’

参考:

https://github.com/B-Con/crypto-algorithms/blob/master/des.c

Base64

密文字符集:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

等于号,即61,0x3D,或者加号,即43或0x2B

更多的可以参考:

https://github.com/B-Con/crypto-algorithms


工具

编译和反编译

>>> from pwn import *
>>> a = 'add ebx,2'
>>> b = asm(a)
>>> b
'\x83\xc3\x02'
>>> c = disasm(b)
>>> c
'   0:   83 c3 02                add    ebx,0x2'

网址:

http://shell-storm.org/online/Online-Assembler-and-Disassembler/


加密算法

PEID的Krypto ANALyzer插件

至少AES和Base64可以鉴别出来


最后

之前博客的图片都看不到了,因为我上传图片的网站好像出事了还是怎样的……



RE Share Tweet +1