buu注册机部分题型汇总一 xor-8086-[GXYCTF2019]luck_guy

buu-xor

测试

首先,无法直接运行,其次,OD无法打开,接下来尝试静态调试

关键函数

通过关键字找到主函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *v3; // rsi
  int result; // eax
  signed int i; // [rsp+2Ch] [rbp-124h]
  char v6[264]; // [rsp+40h] [rbp-110h]
  __int64 v7; // [rsp+148h] [rbp-8h]

  memset(v6, 0, 0x100uLL);
  v3 = (char *)256;
  printf("Input your flag:\n", 0LL);
  get_line(v6, 256LL);
  if ( strlen(v6) != 33 )
    goto LABEL_12;
  for ( i = 1; i < 33; ++i )
    v6[i] ^= v6[i - 1];
  v3 = global;
  if ( !strncmp(v6, global, 0x21uLL) )
    printf("Success", v3);
  else
LABEL_12:
    printf("Failed", v3);
  result = __stack_chk_guard;
  if ( __stack_chk_guard == v7 )
    result = 0;
  return result;
}

代码解析

关键步骤如下,即进行xor操作后与global进行比较

  for ( i = 1; i < 33; ++i )
    v6[i] ^= v6[i - 1];
  v3 = global;
  if ( !strncmp(v6, global, 0x21uLL) )
    printf("Success", v3);

其中global的定义如下

__data:0000000100001050 _global         dq offset aFKWOXZUPFVMDGH
__data:0000000100001050                                         ; DATA XREF: _main+10D↑r
__data:0000000100001050 __data          ends                    ; "f\nk\fw&O.@\x11x\rZ;U\x11p\x19F\x1Fv\"M"...

即前半部分f\nk\fw&O.@\x11x\rZ;U\x11p\x19F\x1Fv\"M因为字符串太长省略了点进去可以看到

__cstring:0000000100000F6E aFKWOXZUPFVMDGH db 'f',0Ah              ; DATA XREF: __data:_global↓o
__cstring:0000000100000F6E                 db 'k',0Ch,'w&O.@',11h,'x',0Dh,'Z;U',11h,'p',19h,'F',1Fh,'v"M#D',0Eh,'g'
__cstring:0000000100000F6E                 db 6,'h',0Fh,'G2O',0

后半段可得f\nk\fw&O.@\x11x\rZ;U\x11p\x19F\x1Fv\"M#D\x0Eg\x06h\x0FG2O

\x两位十六进制表示的ASCII码 代表使用ascii编码,python会自动转换为文本对应字符

最后一位是\x00即字符串结束字符,因为使用""定义会自带因此没有加上

注册机

http://poilzero.sipc115.club/index.php/archives/65/不同的在于

本题的每次xor的修改影响了,下一个值的修改,因此,逆向需要用另一个数组来储存答案

str="f\nk\fw&O.@\x11x\rZ;U\x11p\x19F\x1Fv\"M#D\x0Eg\x06h\x0FG2O"

flag='f'
for i in range(1,len(str)):
    flag+=chr(ord(str[i])^ord(str[i-1]))
print(flag)

运行结果:flag{QianQiuWanDai_YiTongJiangHu}

buu-8086

测试

首先,无法直接运行,其次,OD无法打开,接下来尝试静态调试

关键函数

IDA打开后发现只有两个函数,主函数和sub_10030(),主函数只是调用了这个函数,而sub_10030()只是不断的调用自己(jmp自己)死循环。

按空格查看所有的汇编源码发现一段可疑的部分,这部分没转成汇编,只是单纯彰显了这块的原始数据

seg001:0002                 db 0B9h, 22h, 0, 8Dh, 1Eh, 2 dup(0), 8Bh, 0F9h, 4Fh, 80h
seg001:0002                 db 31h, 1Fh, 0E2h, 0F8h, 8Dh, 16h, 2 dup(0), 0B4h, 9, 0CDh
seg001:0002                 db 21h, 0C3h
seg001:001A                 assume ss:dseg, ds:nothing
seg001:001A

强制转换成汇编(选中后按C,之后Force-Yes)得到以下内容,看起来这段就是真正的加密算法了

seg001:0002                 mov     cx, 22h ; '"'
seg001:0005                 lea     bx, aUDuTZWjQGjzZWz ; "]U[du~|t@{z@wj.}.~q@gjz{z@wzqW~/b;"
seg001:0009
seg001:0009 loc_10039:                              ; CODE XREF: seg001:000F↓j
seg001:0009                 mov     di, cx
seg001:000B                 dec     di
seg001:000C                 xor     byte ptr [bx+di], 1Fh
seg001:000F                 loop    loc_10039
seg001:0011                 lea     dx, aUDuTZWjQGjzZWz ; "]U[du~|t@{z@wj.}.~q@gjz{z@wzqW~/b;"
seg001:0015                 mov     ah, 9
seg001:0017                 int     21h             ; DOS - PRINT STRING
seg001:0017                                         ; DS:DX -> string terminated by "$"
seg001:0019                 retn

代码解析

loop:循环计数器,只要cx大于0就跳转

本处的代码,的含义即把每一个]U[du~|t@{z@wj.}.~q@gjz{z@wzqW~/b;中的字符与0x1F进行xor操作,模拟他的正向操作

注册机

按照思路写注册机

str  = "]U[du~|t@{z@wj.}.~q@gjz{z@wzqW~/b;"
flag = ''
for i in str:
    flag+=chr(ord(i)^0x1F)
print(flag)

运行结果:BJD{jack_de_hu1b1an_xuede_henHa0}$,提交去掉$就好了

buu-[GXYCTF2019]luck_guy

测试

首先,无法直接运行,其次,OD无法打开,接下来尝试静态调试

关键函数

main()-->patch_me(v4);-->get_flag()

关键语句如下

     case 1:
        puts("OK, it's flag:");
        memset(&s, 0, 0x28uLL);
        strcat((char *)&s, f1);  //f1有直接定义,即前半段flag:GXY{do_not_
        strcat((char *)&s, &f2); //f2没有定义
        printf("%s", &s);
        break;
      case 2:
        printf("Solar not like you");
        break;
      case 3:
        printf("Solar want a girlfriend");
        break;
      case 4:
        v6 = 0;
        s = 9180147350284624745LL;
        strcat(&f2, (const char *)&s);
        break;
      case 5:
        for ( j = 0; j <= 7; ++j )
        {
          if ( j % 2 == 1 )
            v1 = *(&f2 + j) - 2;
          else
            v1 = *(&f2 + j) - 1;
          *(&f2 + j) = v1;
        }
        break;

代码解析

首先很容易看到,其中f1有直接定义,即前半段flag:GXY{do_not_,f2没有定义

puts("OK, it's flag:");
memset(&s, 0, 0x28uLL);
strcat((char *)&s, f1);  
strcat((char *)&s, &f2); 
printf("%s", &s);

继续分析可以得,另一半flag。

先是初始化字符串,然后进行简单的加密操作就可以得到

s = 9180147350284624745LL;
strcat(&f2, (const char *)&s);
for ( j = 0; j <= 7; ++j )
{
    if ( j % 2 == 1 )
        v1 = *(&f2 + j) - 2;
    else
        v1 = *(&f2 + j) - 1;
    *(&f2 + j) = v1;
}

其中要说明的是9180147350284624745LL是字符串,因为计算机中大端小端存储问题(最小单位1byte,也就是八位两个十六进制)。

转换成一般理解的字符串需要如下操作

  • 转十八进制
  • 以两位十六进制为单位(1byte 1char)转为单个字符
  • 字符逆序保存

注册机

后半段

str = 9180147350284624745
hst = hex(str)
st1 = ''
for i in range(len(hst)-1, 2, -2):
    tmp = hst[i-1] + hst[i]
    print(int(tmp, 16))
    st1 += chr(int(tmp, 16))
print("---------------------------")
flag = ''
for i in range(8):
    if i % 2 == 1:
        tmp = chr(ord(st1[i])-2)
    else:
        tmp = chr(ord(st1[i])-1)
    flag += tmp
print(flag)

解得hate_me},加上直接给的前半段GXY{do_not_得到答案flag{do_not_hate_me}

Last modification:February 6, 2021
如果觉得我的文章对你有用,请随意赞赏。咖啡(12RMB)进度+100%,一块巧克力(1RMB)进度+6%。
(赞赏请备注你的名称哦!后台记录中来自理工小菜狗)