NewStarCTF2023 WEEK5 RE

这就是 "新生赛" 难度吗??? 。。。
目前也只复现了两道 慢慢补吧~

Fish

隔了好久再来看熟练多了
IDA打开 main啥都没有
看汇编
大量的这种类型的花指令

.text:0000000000401A12                 jz      short near ptr loc_401A16+1
.text:0000000000401A14                 jnz     short near ptr loc_401A16+1

以前我的做法是将这两个全部patch掉 但这种只适用于一两个这种❀的情况
如果有很多的话这种patch会影响到IDA对后续语句的识别 比如这题如果这么patch那么关键常量就找不到了
正确做法是将jnz后的那个指令字节patch为nop(90)
为了方便批量化操作 general打开操作码显示

.text:0000000000401A12 74 03                                   jz      short near ptr loc_401A16+1
.text:0000000000401A14 75 01                                   jnz     short near ptr loc_401A16+1
.text:0000000000401A16

当我们识别到 74 75 后将之后的位置设为90即可

start = 0x4019FC
end = 0x401AD8
while start<end:
    if((get_wide_byte(start)==0x74) and (get_wide_byte(start+2)==0x75)):
        ida_bytes.patch_byte(start+4,0x90)
    start += 1
print("[+] OK !")

这样patch后再将main全部选中按C Force一下就可以得到正常的源码了
这样的话汇编大致是这种形式

.text:0000000000401A17                                                                 ; sub_4019FE+16↑j
.text:0000000000401A17 48 B8 4E 65 77 53 74 61                 mov     rax, 7261745377654Eh
.text:0000000000401A17 72 00
.text:0000000000401A21 48 89 45 10                             mov     [rbp+30h+var_20], rax
.text:0000000000401A25 74 03                                   jz      short loc_401A2A
.text:0000000000401A27 75 01                                   jnz     short loc_401A2A
.text:0000000000401A29 90                                      nop

可以看到这里mov rax ... 这里的值就是 NewStar 这是最初patch会影响到的语句块!
然后main是这个样子

// positive sp value has been detected, the output may be wrong!
__int64 __fastcall sub_4019FE(__int64 a1, __int64 a2, __int64 a3)
{
  char Str1[96]; // [rsp+20h] [rbp-60h] BYREF
  int v5; // [rsp+80h] [rbp+0h]
  int v6; // [rsp+84h] [rbp+4h] BYREF
  __int64 v7[4]; // [rsp+90h] [rbp+10h] BYREF

  sub_402660(a1, a2, a3);
  v7[0] = 0x7261745377654Ei64;
  memset(Str1, 0, sizeof(Str1));
  v5 = 0;
  sub_401951(0i64, &v6);
  scanf("%s", Str1);
  sub_4016C1(v7);
  ((void (__fastcall *)(char *))sub_40188B)(Str1);
  if ( !strcmp(Str1, &Str2) )
    puts("WOW!");
  else
    puts("I believe you can do it!");
  system("pause");
  return 0i64;
}

用FindCrypt插件Ctrl+F一看发现是BlowFish加密
在strcmp那儿可以拿到check值 key猜测是 "NewStar"
找个在线网站解就完了
注意选择 nopadding

flag : flag{YouGotit!!Yougoit!!!!TheFifthPZGALAXYLEVEL}

其实最后发现可以将整个程序按照这种patch处理后Force一下能看到完整程序流
MAIN

int __fastcall MAIN(int argc, const char **argv, const char **envp)
{
  char Str1[96]; // [rsp+20h] [rbp-60h] BYREF
  int v5; // [rsp+80h] [rbp+0h]
  __int64 v6[4]; // [rsp+90h] [rbp+10h] BYREF

  sub_402660(argc, argv, envp);
  v6[0] = 0x7261745377654Ei64;
  memset(Str1, 0, sizeof(Str1));
  v5 = 0;
  sub_401951();
  scanf("%s", Str1);
  sub_4016C1((const char *)v6);
  sub_40188B(Str1);
  if ( !strcmp(Str1, (const char *)&loc_40403F + 1) )
    puts("WOW!");
  else
    puts("I believe you can do it!");
  system("pause");
  return 0;
}

sub_4016C1 应该就是根据NewStar来生成后续密钥

char *__fastcall sub_4016C1(const char *a1)
{
  char *result; // rax
  int v2; // [rsp+24h] [rbp-1Ch] BYREF
  int v3; // [rsp+28h] [rbp-18h] BYREF
  int v4; // [rsp+2Ch] [rbp-14h]
  int v5; // [rsp+30h] [rbp-10h]
  int v6; // [rsp+34h] [rbp-Ch]
  int i; // [rsp+38h] [rbp-8h]
  int j; // [rsp+3Ch] [rbp-4h]

  result = (char *)strlen(a1);
  v4 = (int)result;
  v5 = 0;
  j = 0;
  v6 = 0;
  while ( j <= 17 )
  {
    v5 = 0;
    for ( i = 0; i <= 3; ++i )
    {
      v5 = (v5 << 8) | (unsigned __int8)a1[v6];
      v6 = (v6 + 1) % v4;
    }
    result = (char *)&loc_40407F + 1;
    *(_DWORD *)((char *)&loc_40407F + 4 * j++ + 1) ^= v5;
  }
  v3 = 0;
  v2 = 0;
  for ( j = 0; j <= 17; j += 2 )
  {
    sub_4015DE(&v3, &v2);
    *(_DWORD *)((char *)&loc_40407F + 4 * j + 1) = v3;
    result = (char *)&loc_40407F + 1;
    *(_DWORD *)((char *)&loc_40407F + 4 * j + 5) = v2;
  }
  for ( j = 0; j <= 3; ++j )
  {
    for ( i = 0; i <= 255; i += 2 )
    {
      sub_4015DE(&v3, &v2);
      *(_DWORD *)((char *)&loc_4040FF + 1024 * (__int64)j + 4 * i + 1) = v3;
      result = (char *)&loc_4040FF + 1;
      *(_DWORD *)((char *)&loc_4040FF + 1024 * (__int64)j + 4 * i + 5) = v2;
    }
  }
  return result;
}

sub_40188B 标准BlowFish加密

__int64 __fastcall sub_40188B(const char *a1)
{
  _DWORD *v1; // rbx
  __int64 result; // rax
  unsigned int v3; // [rsp+24h] [rbp-5Ch] BYREF
  unsigned int v4; // [rsp+28h] [rbp-58h] BYREF
  int v5; // [rsp+2Ch] [rbp-54h]
  char *v6; // [rsp+30h] [rbp-50h]
  unsigned int i; // [rsp+3Ch] [rbp-44h]

  v5 = strlen(a1) / 8;
  v6 = (char *)a1;
  for ( i = 0; ; ++i )
  {
    result = i;
    if ( (int)i >= v5 )
      break;
    v4 = sub_403000(*(unsigned int *)v6);
    v3 = sub_403000(*((unsigned int *)v6 + 1));
    sub_4015DE(&v4, &v3);
    *(_DWORD *)v6 = sub_403000(v4);
    v1 = v6 + 4;
    *v1 = sub_403000(v3);
    v6 += 8;
  }
  return result;
}

在sub_4015DE中可以看到BlowFish的常量 0x9216D5D9 和 0x8979FB1B(dword_4040C4)

unsigned int *__fastcall sub_4015DE(unsigned int *a1, unsigned int *a2)
{
  unsigned int *result; // rax
  unsigned int v3; // [rsp+28h] [rbp-8h]
  unsigned int v4; // [rsp+28h] [rbp-8h]
  int i; // [rsp+2Ch] [rbp-4h]

  for ( i = 0; i <= 15; ++i )
  {
    *a1 ^= *(_DWORD *)((char *)&loc_40407F + 4 * i + 1);
    *a2 ^= sub_401530(*a1);
    v3 = *a1;
    *a1 = *a2;
    *a2 = v3;
  }
  v4 = *a1;
  *a1 = *a2;
  *a2 = v4;
  *a2 ^= 0x9216D5D9;
  result = a1;
  *a1 ^= dword_4040C4;
  return result;
}

Genshin

考察的是erlang beam文件逆向
先下载好erlang编译器工具
然后通过这种方式(搜了一圈也不知道怎么找到这条反汇编命令的...)

io:format("~p~n",[beam_disasm:file("genshin.beam")]).

注意结尾要有'.' !!!
可以得到文件的字节码

{beam_file,genshin,
    [{main,1,2},{module_info,0,11},{module_info,1,13}],
    [{vsn,[294325075297162417208450880208266398775]}],
    [{version,"8.3.1"},
     {options,[]},
     {source,
         [47,109,110,116,47,100,47,67,84,70,47,20986,39064,47,50,48,50,51,45,
          56,45,100,117,105,110,101,105,115,97,105,47,103,101,110,115,104,105,
          110,46,101,114,108]}],
    [{function,main,1,2,
         [{label,1},
          {line,1},
          {func_info,{atom,genshin},{atom,main},1},
          {label,2},
          {test,is_nonempty_list,{f,3},[{x,0}]},
          {get_list,{x,0},{x,1},{x,0}},
          {test,is_nil,{f,3},[{x,0}]},
          {move,{x,1},{x,0}},
          {call_only,1,{genshin,check,1}},
          {label,3},
          {move,
              {literal,"Usage: xxxxxxxx genshin.beam <input_string>~n"},
              {x,0}},
          {line,2},
          {call_ext_only,1,{extfunc,io,format,1}}]},
     {function,check,1,5,
         [{line,3},
          {label,4},
          {func_info,{atom,genshin},{atom,check},1},
          {label,5},
          {test,is_list,{f,4},[{x,0}]},
          {allocate,1,1},
          {move,{x,0},{y,0}},
          {move,{literal,[21407,31070,46,46,46,126,110]},{x,0}},
          {line,4},
          {call_ext,1,{extfunc,io,format,1}},
          {move,{integer,1},{x,1}},
          {move,nil,{x,2}},
          {move,{y,0},{x,0}},
          {init_yregs,{list,[{y,0}]}},
          {line,5},
          {call,3,{genshin,transform,3}},
          {line,6},
          {call_ext,1,{extfunc,erlang,list_to_binary,1}},
          {test,is_eq_exact,
              {f,6},
              [{tr,{x,0},{t_bitstring,8,false}},
               {literal,
                   <<107,114,102,103,130,68,118,106,107,119,88,109,131,70,
                     114,130,122,81,111,40,107,77,76,38,52,73,72,101>>}]},
          {move,{literal,[21551,21160,65281,126,110]},{x,0}},
          {line,7},
          {call_ext_last,1,{extfunc,io,format,1},1},
          {label,6},
          {move,{literal,[20851,38381,126,110]},{x,0}},
          {line,8},
          {call_ext_last,1,{extfunc,io,format,1},1}]},
     {function,transform,3,8,
         [{line,9},
          {label,7},
          {func_info,{atom,genshin},{atom,transform},3},
          {label,8},
          {test,is_nonempty_list,{f,9},[{x,0}]},
          {get_list,{x,0},{x,3},{x,0}},
          {line,10},
          {gc_bif,'bxor',
              {f,0},
              4,
              [{x,3},{tr,{x,1},{t_integer,{1,'+inf'}}}],
              {x,3}},
          {gc_bif,'+',{f,0},4,[{tr,{x,3},{t_integer,any}},{integer,4}],{x,3}},
          {line,11},
          {gc_bif,'+',
              {f,0},
              4,
              [{tr,{x,1},{t_integer,{1,'+inf'}}},{integer,1}],
              {x,1}},
          {test_heap,2,4},
          {put_list,{x,3},{x,2},{x,2}},
          {call_only,3,{genshin,transform,3}},
          {label,9},
          {test,is_nil,{f,7},[{x,0}]},
          {move,{x,2},{x,0}},
          {line,9},
          {call_ext_only,1,{extfunc,lists,reverse,1}}]},
     {function,module_info,0,11,
         [{line,0},
          {label,10},
          {func_info,{atom,genshin},{atom,module_info},0},
          {label,11},
          {move,{atom,genshin},{x,0}},
          {call_ext_only,1,{extfunc,erlang,get_module_info,1}}]},
     {function,module_info,1,13,
         [{line,0},
          {label,12},
          {func_info,{atom,genshin},{atom,module_info},1},
          {label,13},
          {move,{x,0},{x,1}},
          {move,{atom,genshin},{x,0}},
          {call_ext_only,2,{extfunc,erlang,get_module_info,2}}]}]}

慢慢分析字节码吧...

这里是最后的check is_eq_exact

{test,is_eq_exact,
              {f,6},
              [{tr,{x,0},{t_bitstring,8,false}},
               {literal,
                   <<107,114,102,103,130,68,118,106,107,119,88,109,131,70,
                     114,130,122,81,111,40,107,77,76,38,52,73,72,101>>}]},

接着往前找到transform函数
在网上搜了搜beam字节码 找到一些例子

    {gc_bif,abs,{f,0},2,[{x,0}],{x,0}}. //用x0去调用bif函数abs,存储结果到x0寄存器,

    {gc_bif,abs,{f,0},2,[{x,1}],{x,1}}. //用x1去调用bif函数abs,存储结果到x1寄存器,

    {gc_bif,'+',{f,0},2,[{x,0},{x,1}],{x,0}}. //执行bif函数+, x0+x1,结果放入x0寄存器

有了这些例子再看transform

{function,transform,3,8,
         [{line,9},
          {label,7},
          {func_info,{atom,genshin},{atom,transform},3},
          {label,8},
          {test,is_nonempty_list,{f,9},[{x,0}]},
          {get_list,{x,0},{x,3},{x,0}},
          {line,10},
          {gc_bif,'bxor',
              {f,0},
              4,
              [{x,3},{tr,{x,1},{t_integer,{1,'+inf'}}}],
              {x,3}},
          {gc_bif,'+',{f,0},4,[{tr,{x,3},{t_integer,any}},{integer,4}],{x,3}},
          {line,11},
          {gc_bif,'+',
              {f,0},
              4,
              [{tr,{x,1},{t_integer,{1,'+inf'}}},{integer,1}],
              {x,1}},
          {test_heap,2,4},
          {put_list,{x,3},{x,2},{x,2}},
          {call_only,3,{genshin,transform,3}},
          {label,9},
          {test,is_nil,{f,7},[{x,0}]},
          {move,{x,2},{x,0}},
          {line,9},
          {call_ext_only,1,{extfunc,lists,reverse,1}}]},

重点在这一部分:

{line,10},
          {gc_bif,'bxor',
              {f,0},
              4,
              [{x,3},{tr,{x,1},{t_integer,{1,'+inf'}}}],
              {x,3}},
          {gc_bif,'+',{f,0},4,[{tr,{x,3},{t_integer,any}},{integer,4}],{x,3}},
          {line,11},
          {gc_bif,'+',
              {f,0},
              4,
              [{tr,{x,1},{t_integer,{1,'+inf'}}},{integer,1}],
              {x,1}},

bxor这里:

          {gc_bif,'bxor',
              {f,0},
              4,
              [{x,3},{tr,{x,1},{t_integer,{1,'+inf'}}}],
              {x,3}},

大致是 {x,1} xor (t_integer+1) 然后结果存给 {x,3}

再看下面的'+':

{gc_bif,'+',{f,0},4,[{tr,{x,3},{t_integer,any}},{integer,4}],{x,3}},

这里是 {x,3}+4这种运算 最后结果存回 {x,3}
再下面的'+'应该是循环的ecx++

所以加密逻辑:

flag[i] = (flag[i]^(i+1))+4

从enc[]逆回去即可得到flag
flag: flag{Funny_erLang_x0r__😃__} (神奇的博客园把 ': )'给编译成这个emoji...)



这种搜索资料的能力和通过例子学习新知识的能力也要多培养 练习
不得不感慨赛时做出了的3位佬tql orz

posted @ 2023-12-21 22:22  N0zoM1z0  阅读(48)  评论(0编辑  收藏  举报