[AntCTF x D^3CTF 2022] Reverse部分赛题复现 - 1

(真的是复现,思路基本来自各大爹的wp

D3MUG

打开发现是个音游

题目说打出AP就能拿到flag,但我相信这个速度没人能在手机上打出AP(

在打开游戏的过程中我们发现这是个unity开发的游戏,那么他的逻辑重点都在libil2cpp.so里面

我们可以考虑用Il2CppDumper导出libil2cpp.so和global-metadata.dat,然后再用ida_with_struct.py辅助ida打开.so文件进行分析

由于函数太多,我们尝试搜索字符串d3mug,找到了这个函数

1648727844070

sub_5609A4内发现了

程序可能会抛出Unable to load DLL,那这里应该是调用了其他的玩意

在libil2cpp.so同一个目录下有libd3mug.so,ida打开会发现其中有update函数,根据GameManager__update内含字符串d3mug和update,我们合理猜测这里是调用了libd3mug.so内的update()

在update函数末尾其调用了Server::run函数

这只能猜是flag的加解密函数了

另外,字符串d3mug还有一处地方用到了

这个函数名字我们应该认为他是最后打印得分页面的函数,那么flag很可能就是从这里输出的

并且,字符串d3mug后面的"get"也对应了libd3mug.so的另一个函数get()

这也应该是和flag的加解密有关的

现在该考虑找到run/get的参数了

对GameManager__update进行交叉引用可以看到函数GameManager__NoteHit

由音游的知识知道按的拍子叫note,那这里就是在看按的拍子的结果,参数名字preciseTime和level,可以猜测前面的是在判断现在是曲子哪个时间点,后面的是判断现在的拍子打的如何(miss/good/perfect),后面调用update的时候传入的是参数PreciesTime,那么update关联的run函数的参数也应为时间点

用AssestStudio解包,找到关于时间的资源

(如果你直接找到的hitpoints,不知道3选1该选哪个,显然你打的谱子是Chrome VOX)

(显然大家都该去muse dash上试试这首歌有多难打🥺)

可以看到第一个数是哪一个拍子,第二个数是哪个时间点

然后就该解密run函数了,然而我不会写🥺

贴一篇dalao写的exp(好像是W&M的大爹的

#include <stdio.h>
#include <random>
#include <Windows.h>

using namespace std;

const DWORD hitp[] = { 0,0,0,146,292,292,439,512,585,585,658,731,804,878,1024,1170,1170,1317,1463,1463,1609,1682,1756,1756,1902,2048,2195,2341,2341,2487,2634,2634,2780,2853,2926,2926,3073,3146,3219,3219,3365,3439,3512,3512,3658,3804,3878,3951,4024,4097,4097,4243,4390,4682,4682,4682,4829,4975,4975,5121,5195,5268,5341,5414,5487,5560,5560,5853,5853,5999,6146,6146,6292,6365,6439,6439,6585,6731,6731,6731,7024,7024,7170,7317,7317,7463,7536,7609,7609,7682,7756,7829,7902,7902,7975,8048,8121,8195,8341,8487,8634,8780,9073,9073,9073,9219,9365,9365,9512,9658,9658,9804,9878,9951,9951,10097,10243,10243,10243,10390,10463,10536,10536,10682,10829,10829,10975,11121,11121,11268,11414,11414,11560,11707,11707,11853,11999,11999,11999,12146,12292,12292,12439,12439,12585,12585,12585,12731,12878,12951,13024,13097,13170,13170,13317,13463,13463,13463,13609,13756,13756,13756,13902,14048,14048,14195,14341,14487,14634,14634,14926,14926,14926,15219,15219,15219,15365,15365,15512,15512,15658,15804,15804,15951,16024,16097,16097,16170,16243,16317,16390,16390,16536,16682,16682,16829,16902,16975,16975,17121,17268,17268,17268,17414,17560,17634,17707,17780,17853,17926,17999,18073,18146,18146,18292,18439,18439,18731,18731,18731,18878,19024,19024,19024,19170,19243,19317,19463,19609,19609,19609,19756,19829,19902,20048,20195,20195,20341,20487,20487,20634,20780,20780,20926,21073,21073,21219,21365,21365,21365,21512,21585,21658,21658,21804,21951,21951,21951,22097,22243,22317,22390,22463,22536,22536,22609,22682,22756,22829,22829,22975,23121,23121,23268,23414,23560,23707,23780,23853,23926,23999,23999,24073,24146,24219,24292,24365,24439,24512,24585,24585,24731,24731,24878,24878,24878,25024,25170,25170,25317,25390,25463,25463,25609,25756,25756,25756,25902,25902,26048,26048,26195,26195,26341,26341,26414,26487,26487,26560,26634,26634,26780,26780,26926,27219,27512,27585,27658,27731,27804,27804,28097,28097,28390,28682,28682,28975,29268,29268,29560,29560,29853,29853,30146,30439,30439,30731,31024,31024,31317,31609,31609,31902,32195,32195,32487,32780,32780,32780,33365,33365,33365,33951,33951,34243,34536,34536,34829,35121,35121,35414,35707,35707,35707,35999,36292,36585,36878,36878,37024,37024,37170,37170,37463,37463,37463,37609,37756,37756,37902,38048,38048,38195,38341,38341,38487,38634,38634,38780,38926,39073,39219,39365,39512,39658,39804,39804,39951,40097,40097,40243,40390,40390,40536,40682,40829,40975,40975,41121,41268,41414,41560,41707,41853,41999,42146,42146,42292,42292,42439,42585,42731,42731,42878,42878,43024,43170,43317,43317,43463,43463,43609,43609,43682,43756,43756,43829,43902,43902,44048,44048,44195,44195,44341,44341,44487,44560,44634,44707,44780,44853,44926,44999,45073,45146,45219,45292,45365,45439,45512,45585,45658,45658,45804,45951,45951,46097,46243,46243,46536,46536,46536,46829,46829,46902,46975,47121,47121,47268,47414,47414,47560,47634,47707,47707,47853,47926,47999,47999,48146,48292,48292,48439,48585,48585,48731,48878,48878,49024,49170,49170,49243,49317,49463,49463,49609,49756,49756,49902,49975,50048,50048,50121,50195,50268,50341,50341,50487,50487,50707,50707,50926,50926,51073,51219,51365,51512,51512,51585,51658,51804,51804,51951,52097,52097,52170,52243,52317,52390,52390,52536,52609,52682,52682,52829,52975,52975,53121,53268,53268,53414,53560,53560,53707,53853,53853,53926,53999,54073,54146,54146,54219,54292,54365,54439,54439,54512,54585,54658,54731,54731,54878,54878,55024,55024,55024,55317,55317,55317,55609,55609,55609,55902,55902,55902,56195,56268,56341,56487,56487,56634,56780,56780,56926,56999,57073,57073,57219,57292,57365,57365,57512,57658,57658,57804,57951,57951,58097,58243,58243,58390,58536,58536,58609,58682,58829,58829,58975,59121,59121,59268,59341,59414,59414,59560,59634,59707,59707,59853,59926,59999,59999,60073,60292,60292,60439,60585,60585,60731,60878,60878,60951,61024,61024,61170,61170,61317,61317,61463,61463,61463,61536,61609,61609,61756,61756,61902,61902,62048,62048,62048,62121,62195,62195,62341,62341,62414,62487,62560,62634,62634,62780,62780,62926,62926,63073,63073,63219,63219,63292,63365,63439,63512,63512,63585,63658,63731,63804,63804,63878,63951,64024,64097,64097,64170,64243,64317,64390,64390,64536,64536,64609,64682,64829,64975,65121,65268,65414,65560,65560,65707,65853,65999,66146,66146,66439,66585,66878,67170,67317,67317,67609,67902,68048,68195,68341,68487,68487,68780,68926,69073,69219,69365,69512,69658,69658,69804,69951,70243,70390,70536,70682,70829,70829,71121,71268,71560,71853,71999,71999,72292,72585,72731,72878,73024,73170,73317,73463,73609,73609,73756,73975,74195,74341,74341,74634,74707,74780,74926,74926,75073,75073,75219,75219,75219,75365,75512,75512,75658,75658,75804,75804,75804,75951,76097,76097,76390,76390,76390,76536,76682,76682,76829,76829,76975,76975,76975,77268,77268,77414,77560,77560,77561,77707,77853,77853,77999,77999,78146,78146,78146,78292,78439,78439,78731,78732,78732,78878,79024,79024,79170,79171,79317,79317,79463,79609,79609,79756,79902,79902,80048,80195,80341,80341,80487,80487,80634,80780,80780,80926,80926,81073,81073,81073,81219,81365,81512,81512,81658,81658,81658,81951,81951,81951,82097,82243,82243,82390,82536,82682,82682,82829,82829,82829,82975,83121,83121,83268,83414,83414,83560,83707,83853,83853,83999,83999,83999,84292,84292,84365,84439,84512,84585,84585,84731,84804,84878,84878,84951,85024,85097,85170,85170,85317,85390,85463,85463,85536,85609,85682,85756,85756,85829,85902,85975,86048,86048,86121,86195,86268,86341,86341,86487,86634,86634,86707,86780,86853,86926,86926,87073,87146,87219,87219,87292,87365,87439,87512,87512,87658,87804,87804,87878,87951,88024,88097,88097,88170,88243,88317,88390,88390,88536,88609,88682,88682,88829,88975,88975,89121,89121,89268,89268,89414,89414,89560,89560,89707,89707,89853,89853,89999,89999,90146,90146,90292,90292,90439,90439,90585,90585,90731,90731,90878,90878,91024,91024,91170,91170,91317,91317,91390,91463,91536,91609,91682,91756,91829,91902,91975,92048,92121,92195,92268,92341,92634,92780,92926,93219,93365,93365,93365,93365,93658,93658,93804,93878,93951,93951,94097,94243,94317,94390,94463,94536,94536,94682,94829,94829,94975,95121,95121,95268,95414,95487,95560,95634,95707,95707,95853,95853,95999,95999,96146,96292,96292,96292,96439,96585,96585,96658,96731,96804,96878,96878,97024,97170,97170,97317,97390,97463,97463,97609,97756,97756,97829,97902,98048,98048,98048,98195,98341,98341,98487,98560,98634,98634,98780,98926,98926,99073,99219,99219,99365,99512,99512,99658,99804,99804,99951,100097,100170,100243,100317,100390,100390,100536,100682,100682,100829,100975,100975,100975,101121,101268,101268,101341,101414,101487,101560,101560,101707,101853,101853,101926,101999,102073,102146,102146,102292,102439,102439,102439,102585,102658,102731,102731,102878,103024,103024,103024,103170,103243,103317,103317,103317,103463,103609,103682,103756,103829,103902,103902,104048,104195,104195,104341,104487,104487,104487,104634,104780,104853,104926,104999,105073,105073,105219,105365,105365,105512,105658,105658,105658,105804,105951,105951,106097,106170,106243,106243,106317,106390,106536,106536,106682,106756,106829,106829,106829,106975,107121,107121,107268,107268,107414,107414,107414,107560,107707,107707,107707,107853,107999,107999,107999,108146,108292,108292,108439,108585,108585,108731,108878,108878,108878,109024,109170,109170,109317,109463,109463,109536,109609,109682,109756,109756,109902,110048,110048,110048,110195,110195,110341,110341,110341,110487,110487,110634,110634,110634,110780,110780,110926,110926,110926,111073,111073,111219,111219,111219,111365,111512,111658,111731,111804,111878,111951,112024,112097,112097,112097,112390,112390,112536,112682,112682,112682,112829,112975,112975,113121,113268,113268,113414,113560,113560,113707,113853,113853,113999,114146,114219,114292,114365,114439,114439,114585,114731,114731,114878,115024,115024,115024,115170,115317,115317,115463,115536,115609,115609,115756,115902,115902,115975,116048,116121,116195,116195,116268,116341,116414,116487,116487,116560,116634,116707,116780,116780,116926,117073,117073,117219,117365,117365,117512,117658,117658,117804,117878,117951,117951,118097,118243,118243,118390,118536,118536,118682,118829,118902,118975,119048,119121,119121,119268,119414,119414,119560,119707,119707,119853,119999,119999,120146,120292,120292,120439,120439,120731,121024,121170,121463,121536,121609,121682,121756,121756,121756,121902,122048,122048,122048,122195,122341,122341,122341,122487,122560,122634,122634,122634,122780,122926,122926,122926,123073,123219,123219,123219,123365,123512,123512,123512,123585,123658,123731,123804,123804,123804,123951,124097,124097,124097,124243,124390,124390,124390,124536,124682,124682,124682,124829,124975,124975,124975,125121,125268,125268,125268,125414,125487,125560,125560,125560,125707,125853,125853,125853,125999,126146,126146,126146,126292,126439,126439,126439,126585,126585,126731,126731,126878,126878,127024,127024,127024,127170,127170,127317,127317,127463,127463,127609,127609,127609,127756,127756,127902,127902,128048,128048,128195,128195,128268,128341,128341,128414,128487,128487,128560,128634,128707,128780,128780,128853,128926,128999,129073,129146,129219,129292,129365,129365,129439,129512,129585,129658,129731,129804,129878,129951,129951,130024,130097,130170,130243,130243,130317,130390,130463,130536,130536,130682,130756,130829,130829,130829,130975,130975,131121,131195,131268,131341,131560,131707,131707,131780,131853,131926,132146,132292,132365,132439,132512,132731,132878,132878,132951,133024,133097,133463,133463,133756,134048,134048,134048,134341,134634,134634,134926,134926,135219,135219,135219,135512,135512,135658,135658,135804,135804,135951,135951,136097,136097,136243,136243,136390,136390,136536,136536,136609,136682,136682,136829,136829,136902,136975,136975,137121,137121,137268,137268,137414,137414,137560,137560,137707,137707,137780,137853,137926,137999,137999,138073,138146,138146,138219,138292,138365,138439,138439,138512,138585,138658,138731,138731,138804,138878,138951,139024,139024,139097,139170,139243,139317,139317,139463,139463,139609,139609,139756,139756,139902,139902,140195,140195,140195,140195 };

DWORD __ROR4__(DWORD a1, char a2)
{
  return (a1 >> a2) | (a1 << (32 - a2));
}

int rounds(uint8_t* bytes, unsigned int a2, int a3)
{
  DWORD* v3; // r4
  DWORD v4; // r12
  DWORD v5[2]; // r5
  DWORD v6; // r3
  DWORD result; // r0

  v3 = (DWORD*)((char*)bytes + a3);
  v4 = *(DWORD*)((char*)bytes + a3);
  *(DWORD64*)&v5[0] = *(DWORD64*)((char*)bytes + a3 + 4);
  v6 = *(DWORD*)((char*)bytes + a3 + 12);
  *(DWORD*)((char*)bytes + a3) = *(&v5[0] + 1);
  result = v4 ^ __ROR4__(*(&v5[0] + 1) ^ a2, 19);
  v3[3] = v5[0] ^ __ROR4__(v6, 18) ^ __ROR4__(*(&v5[0] + 1) ^ a2, 19);
  v3[1] = v6;
  v3[2] = result;
  return result;
}

int main(int argc, char const* argv[])
{
  unsigned char enc_bytes[] =
  {
    0x3C, 0xAC, 0x92, 0x6F, 0x44, 0xA1, 0xC1, 0x17, 0xFD, 0x62,
    0x60, 0xDD, 0x63, 0xF8, 0xE3, 0x2A, 0x5E, 0x75, 0x78, 0xBE,
    0x59, 0x46, 0x33, 0xF6, 0x2E, 0x64, 0x61, 0x8A, 0x27, 0x93,
    0x21, 0x7D, 0x00
  };
  mt19937 rng(-196167794);
  for (int i = 0; i < 1608; ++i)
  {
    if (rng() % 7 >= 3)
    {
      rounds(enc_bytes, rng(), hitp[i] & 0xF);
    }
  }
  printf("%s\n", enc_bytes);
  getchar();
  return 0;
}

官方给出了另一种解法frida,到时候学了再试试(认真脸

d3w0w

官方wp说的是wow64,32位转64位然后做混淆,又是没见过的东西呜呜呜

int __cdecl main(int argc, const char **argv, const char **envp)
{
  _DWORD v4[11]; // [esp+0h] [ebp-30h] BYREF
  BOOL v5; // [esp+2Ch] [ebp-4h]

  dword_4262F0 = (int)NtCurrentTeb()->WOW32Reserved;
  memset(v4, 0, 0x27u);
  sub_402100("%39s", (const char *)v4);
  v5 = sub_401000(v4, &unk_4262F8) || sub_401220(&unk_4262F8, v4[0]);
  v4[10] = v5;
  if ( v5 )
    sub_402090("you lose\n", v4[0]);
  else
    sub_402090("you win\n", v4[0]);
  return 0;
}

主函数逻辑非常简单,就是通过sub_401000和401220判断真假

int __cdecl sub_401000(int a1, int a2)
{
  int v3; // [esp+0h] [ebp-10h]
  int v4; // [esp+8h] [ebp-8h]
  int v5; // [esp+Ch] [ebp-4h]

  v5 = 0;
  v4 = 0;
  v3 = 6;
  if ( *(_DWORD *)a1 != 1952658276 ) // 'tc3d'
    return 1;
  if ( *(_WORD *)(a1 + 4) != 31590 ) // '{f'
    return 1;
  if ( *(_BYTE *)(a1 + 6) != 50 ) // '2'
    return 1;
  while ( *(_BYTE *)(v3 + a1) != 125 ) // '}'
  {
    switch ( *(_BYTE *)(v3 + a1) )
    {
      case '1':
        *(_DWORD *)(a2 + 24 * v5 + 4 * v4) |= 8u;
        *(_DWORD *)(a2 + 24 * --v5 + 4 * v4) |= 2u;
        goto LABEL_14;
      case '2':
        *(_DWORD *)(a2 + 24 * v5 + 4 * v4) |= 2u;
        *(_DWORD *)(a2 + 24 * ++v5 + 4 * v4) |= 8u;
        goto LABEL_14;
      case '3':
        *(_DWORD *)(a2 + 24 * v5 + 4 * v4) |= 4u;
        *(_DWORD *)(a2 + 24 * v5 + 4 * v4-- - 4) |= 1u;
        goto LABEL_14;
      case '4':
        *(_DWORD *)(a2 + 24 * v5 + 4 * v4) |= 1u;
        *(_DWORD *)(a2 + 24 * v5 + 4 * v4++ + 4) |= 4u;
LABEL_14:
        if ( v5 < 0 || v4 < 0 || v5 > 5 || v4 > 5 )
          return 1;
        ++v3;
        break;
      default:
        return 1;
    }
  }
  return 0;
}

这里可以发现flag的格式为d3ctf{[1-4]}并且有32个1-4,开头的是个2,而且这个代码逻辑很难让人不猜测是个迷宫题,1234控制方向。

经过分析,他确实是

首先,a2存储map,v4 v5分别控制行列,并且该结构对a2进行了初始化。我们将1 2 4 8看做4位二进制数的4个位,就可以直观地发现初始化操作就是让该节点和走到的下一位节点的对应数位的值置为1,容易发现,1234分别控制上下左右,且第一步向下。

然后看sub_401220发现不是很对劲,有一堆寄存器赋值的操作,这里应该就是官方说的通过wow64的特性做的混淆

经过百度,发现sub_402510函数中

402514的push 33以及后面的retf就是32位调用64位的标志

这方面知识可以看看这篇博客

在x64系统下的进程是有32位和64位两种工作模式,这两种工作模式的区别在于CS寄存器。32位模式时,CS = 0x23;64位模式时,CS = 0x33。

这两种工作模式是可以进行切换的,一般会通过retf指令,一条retf指令等效于以下2条汇编指令

pop ip
pop cs

如果此时栈中有0x33,则会将0x33弹出到CS寄存器中,实现32位程序切换到64位代码的过程。所以retf是识别32位程序调用64位代码的重要标志。

那考虑到代码的二进制是不会变的,把64位函数的代码dump下来再放进ida64分析是可行的

010 editor真是好文明,选中这些hex,右键然后save selection直接dump出exe

然后用ida64打开,选64-bit mode,在最开始按P创建函数,就可以看到正常些的伪代码了

__int64 sub_0()
{
  _DWORD *v0; // rcx
  int v2; // [rsp+0h] [rbp-A8h]
  int v3; // [rsp+0h] [rbp-A8h]
  int v4; // [rsp+0h] [rbp-A8h]
  int v5; // [rsp+4h] [rbp-A4h]
  int v6; // [rsp+4h] [rbp-A4h]
  int v7; // [rsp+4h] [rbp-A4h]
  int i; // [rsp+8h] [rbp-A0h]
  int j; // [rsp+Ch] [rbp-9Ch]
  int v10; // [rsp+10h] [rbp-98h]
  int v11; // [rsp+14h] [rbp-94h]
  int k; // [rsp+18h] [rbp-90h]
  int m; // [rsp+1Ch] [rbp-8Ch]
  unsigned int v14; // [rsp+20h] [rbp-88h]
  unsigned int v15; // [rsp+24h] [rbp-84h]
  unsigned int v16; // [rsp+28h] [rbp-80h]
  unsigned int v17; // [rsp+2Ch] [rbp-7Ch]
  unsigned int v18; // [rsp+30h] [rbp-78h]
  unsigned int v19; // [rsp+34h] [rbp-74h]
  int v20[4]; // [rsp+38h] [rbp-70h]
  int v21[10]; // [rsp+48h] [rbp-60h]
  __int64 v22; // [rsp+70h] [rbp-38h]
  __int64 v23; // [rsp+78h] [rbp-30h]
  __int64 v24; // [rsp+80h] [rbp-28h]
  __int64 v25; // [rsp+88h] [rbp-20h]
  __int64 v26; // [rsp+90h] [rbp-18h]
  __int64 v27; // [rsp+98h] [rbp-10h]
  _DWORD *retaddr; // [rsp+B0h] [rbp+8h]

  MEMORY[0x12F0]((unsigned int)retaddr);
  retaddr = v0;
  v20[0] = 0;
  v20[1] = 14;
  v20[2] = 20;
  v21[0] = 4;
  v21[1] = 13;
  v21[2] = 15;
  v21[3] = 21;
  v21[4] = 24;
  v21[5] = 31;
  v21[6] = 32;
  v21[7] = 41;
  v21[8] = 45;
  v21[9] = 53;
  for ( i = 0; i < 6; ++i )
  {
    for ( j = 0; j < 6; ++j )
    {
      if ( retaddr[6 * i + j] > 0xFu )
        return MEMORY[0x1301]();
      v14 = retaddr[6 * i + j] % 0x10u / 8;
      v22 = j;
      v15 = retaddr[6 * i + j] % 8u / 4 + v14;
      v23 = j;
      v16 = retaddr[6 * i + j] % 4u / 2 + v15;
      v24 = j;
      if ( retaddr[6 * i + j] % 2u + v16 > 2 || !j && retaddr[6 * i] % 8u / 4 )
        return MEMORY[0x1301]();
      if ( j == 5 && retaddr[6 * i + 5] % 2u || !i && retaddr[j] % 0x10u / 8 || i == 5 && retaddr[j + 30] % 4u / 2 )
        return MEMORY[0x1301]();
    }
  }
  for ( k = 0; (unsigned __int64)k < 3; ++k )
  {
    v2 = v20[k] / 10;
    v5 = v20[k] % 10;
    if ( retaddr[6 * v2 + v5] % 0x10u / 8 && retaddr[6 * v2 + v5] % 4u / 2 )
      return MEMORY[0x1301]();
    if ( retaddr[6 * v2 + v5] % 8u / 4 && retaddr[6 * v2 + v5] % 2u )
      return MEMORY[0x1301]();
    v17 = retaddr[6 * v2 + v5] % 0x10u / 8;
    v25 = v5;
    v18 = retaddr[6 * v2 + v5] % 4u / 2 + v17;
    v26 = v5;
    v19 = retaddr[6 * v2 + v5] % 2u + v18;
    v27 = v5;
    if ( retaddr[6 * v2 + v5] % 8u / 4 + v19 != 2 )
      return MEMORY[0x1301]();
    if ( retaddr[6 * v2 + v5] % 0x10u / 8 )
    {
      if ( !(retaddr[6 * v2 - 6 + v5] % 0x10u / 8) )
        return MEMORY[0x1301]();
    }
    else if ( retaddr[6 * v2 + v5] % 4u / 2 )
    {
      if ( !(retaddr[6 * v2 + 6 + v5] % 4u / 2) )
        return MEMORY[0x1301]();
    }
    else if ( retaddr[6 * v2 + v5] % 8u / 4 )
    {
      if ( !(retaddr[6 * v2 - 1 + v5] % 8u / 4) )
        return MEMORY[0x1301]();
    }
    else if ( retaddr[6 * v2 + v5] % 2u && !(retaddr[6 * v2 + 1 + v5] % 2u) )
    {
      return MEMORY[0x1301]();
    }
  }
  for ( m = 0; (unsigned __int64)m < 0xA; ++m )
  {
    v3 = v21[m] / 10;
    v6 = v21[m] % 10;
    if ( (!(retaddr[6 * v3 + v6] % 0x10u / 8) || !(retaddr[6 * v3 + v6] % 4u / 2))
      && (!(retaddr[6 * v3 + v6] % 8u / 4) || !(retaddr[6 * v3 + v6] % 2u))
      || retaddr[6 * v3 + v6] % 0x10u / 8
      && retaddr[6 * v3 + v6] % 4u / 2
      && !(retaddr[6 * v3 - 6 + v6] % 8u / 4)
      && !(retaddr[6 * v3 - 6 + v6] % 2u)
      && !(retaddr[6 * v3 + 6 + v6] % 8u / 4)
      && !(retaddr[6 * v3 + 6 + v6] % 2u)
      || retaddr[6 * v3 + v6] % 8u / 4
      && retaddr[6 * v3 + v6] % 2u
      && !(retaddr[6 * v3 + 1 + v6] % 0x10u / 8)
      && !(retaddr[6 * v3 + 1 + v6] % 4u / 2)
      && !(retaddr[6 * v3 - 1 + v6] % 0x10u / 8)
      && !(retaddr[6 * v3 - 1 + v6] % 4u / 2) )
    {
      return MEMORY[0x1301]();
    }
  }
  v10 = 0;
  v11 = 0;
  v4 = 0;
  v7 = 0;
  if ( *retaddr % 0x10u / 8 )
  {
    v4 = -1;
    while ( 1 )
    {
LABEL_67:
      if ( !(retaddr[6 * v4 + v7] % 0x10u / 8) || v4 - 1 == v10 && v7 == v11 )
      {
        if ( !(retaddr[6 * v4 + v7] % 4u / 2) || v4 + 1 == v10 && v7 == v11 )
        {
          if ( !(retaddr[6 * v4 + v7] % 8u / 4) || v4 == v10 && v7 - 1 == v11 )
          {
            if ( !(retaddr[6 * v4 + v7] % 2u) || v4 == v10 && v7 + 1 == v11 )
              return MEMORY[0x1301]();
            v10 = v4;
            v11 = v7++;
          }
          else
          {
            v10 = v4;
            v11 = v7--;
          }
        }
        else
        {
          v10 = v4;
          v11 = v7;
          ++v4;
        }
      }
      else
      {
        v10 = v4;
        v11 = v7;
        --v4;
      }
      if ( !v4 && !v7 )
        return MEMORY[0x1301]();
    }
  }
  if ( *retaddr % 4u / 2 )
  {
    v4 = 1;
    goto LABEL_67;
  }
  if ( *retaddr % 8u / 4 )
  {
    v7 = -1;
    goto LABEL_67;
  }
  if ( *retaddr % 2u )
  {
    v7 = 1;
    goto LABEL_67;
  }
  return MEMORY[0x1301]();
}

有点多,我们一个循环一个循环来看

循环1

for ( i = 0; i < 6; ++i )
{
    for ( j = 0; j < 6; ++j )
    {
        if ( retaddr[6 * i + j] > 0xFu )
            return MEMORY[0x1301]();
        v14 = retaddr[6 * i + j] % 0x10u / 8;
        v22 = j;
        v15 = retaddr[6 * i + j] % 8u / 4 + v14;
        v23 = j;
        v16 = retaddr[6 * i + j] % 4u / 2 + v15;
        v24 = j;
        if ( retaddr[6 * i + j] % 2u + v16 > 2 || !j && retaddr[6 * i] % 8u / 4 )
            return MEMORY[0x1301]();
        if ( j == 5 && retaddr[6 * i + 5] % 2u || !i && retaddr[j] % 0x10u / 8 || i == 5 && retaddr[j + 30] % 4u / 2 )
            return MEMORY[0x1301]();
    }
}

这里是将整个6x6的地图全部遍历了一次,那么这里的条件全局都得满足,比如下面这一条

  • retaddr[6 * i + j] > 0xFu: 节点的值不能大于15

那我们打表吧

那这个循环的约束就显而易见了

  • retaddr[6 * i + j] % 2u + v16 > 2:不能为7 11 13 14 15
  • !j && retaddr[6 * i] % 8u / 4:第一列不能为4 5 6 7 12 13 14 15
  • j == 5 && retaddr[6 * i + 5] % 2u:最后一列不能为1 3 5 7 9 11 13 15
  • !i && retaddr[j] % 0x10u / 8:第一行不能为8 9 10 11 12 13 14 15
  • i == 5 && retaddr[j + 30] % 4u / 2:最后一行不能为2 3 6 7 10 11 14 15

循环2

for ( k = 0; (unsigned __int64)k < 3; ++k )
{
    v2 = v20[k] / 10; // 循环为0 1 2
    v5 = v20[k] % 10; // 循环为0 4 0
    // 可以发现下面在检测(0,0) (1,4) (2,0)三个节点
    if ( retaddr[6 * v2 + v5] % 0x10u / 8 && retaddr[6 * v2 + v5] % 4u / 2 )
        // 不能为10 11 14 45
        return MEMORY[0x1301]();
    if ( retaddr[6 * v2 + v5] % 8u / 4 && retaddr[6 * v2 + v5] % 2u )
        // 不能为5 7 13 15
        return MEMORY[0x1301]();
    v17 = retaddr[6 * v2 + v5] % 0x10u / 8;
    v25 = v5;
    v18 = retaddr[6 * v2 + v5] % 4u / 2 + v17;
    v26 = v5;
    v19 = retaddr[6 * v2 + v5] % 2u + v18;
    v27 = v5;
    if ( retaddr[6 * v2 + v5] % 8u / 4 + v19 != 2 )
        // 必须为3 5 6 9 10 12
        return MEMORY[0x1301]();
    // 显然,这三个点的值必须为3 6 9 12其中的某值
    
    if ( retaddr[6 * v2 + v5] % 0x10u / 8 ) // 值为9 12时
    {
        if ( !(retaddr[6 * v2 - 6 + v5] % 0x10u / 8) ) // 上一行得是8-15
            return MEMORY[0x1301]();
    }
    else if ( retaddr[6 * v2 + v5] % 4u / 2 ) // 值为3 6时
    {
        if ( !(retaddr[6 * v2 + 6 + v5] % 4u / 2) ) // 下一行得是2 3 6 7 10 11 14 15
            return MEMORY[0x1301]();
    }
    else if ( retaddr[6 * v2 + v5] % 8u / 4 ) // 值为6 12时
    {
        if ( !(retaddr[6 * v2 - 1 + v5] % 8u / 4) ) // 上一列得是4 5 6 7 12 13 14 15
            return MEMORY[0x1301]();
    }
    else if ( retaddr[6 * v2 + v5] % 2u && !(retaddr[6 * v2 + 1 + v5] % 2u) ) // 值为3 9时
    {
        return MEMORY[0x1301](); // 下一列得是奇数
    }
}

可以根据上面的真值表来整,看注释吧。

循环3

for ( m = 0; (unsigned __int64)m < 0xA; ++m )
{
    v3 = v21[m] / 10;
    v6 = v21[m] % 10;
    // (0, 4) (1, 3) (1, 5) (2, 1) (2, 4) (3, 1) (3, 2) (4, 1) (4, 5) (5, 3)
    if ( (!(retaddr[6 * v3 + v6] % 0x10u / 8) || !(retaddr[6 * v3 + v6] % 4u / 2))
        && (!(retaddr[6 * v3 + v6] % 8u / 4) || !(retaddr[6 * v3 + v6] % 2u))
        || retaddr[6 * v3 + v6] % 0x10u / 8
        && retaddr[6 * v3 + v6] % 4u / 2
        && !(retaddr[6 * v3 - 6 + v6] % 8u / 4)
        && !(retaddr[6 * v3 - 6 + v6] % 2u)
        && !(retaddr[6 * v3 + 6 + v6] % 8u / 4)
        && !(retaddr[6 * v3 + 6 + v6] % 2u)
        || retaddr[6 * v3 + v6] % 8u / 4
        && retaddr[6 * v3 + v6] % 2u
        && !(retaddr[6 * v3 + 1 + v6] % 0x10u / 8)
        && !(retaddr[6 * v3 + 1 + v6] % 4u / 2)
        && !(retaddr[6 * v3 - 1 + v6] % 0x10u / 8)
        && !(retaddr[6 * v3 - 1 + v6] % 4u / 2) )
    {
        return MEMORY[0x1301]();
    }
}

这个更是个重量级,我们分开来看

约束1

   (!(retaddr[6 * v3 + v6] % 0x10u / 8) || !(retaddr[6 * v3 + v6] % 4u / 2))
&& (!(retaddr[6 * v3 + v6] % 8u / 4) || !(retaddr[6 * v3 + v6] % 2u))

只能为5 7 10 11 13 14 15

约束2

   retaddr[6 * v3 + v6] % 0x10u / 8
&& retaddr[6 * v3 + v6] % 4u / 2
&& !(retaddr[6 * v3 - 6 + v6] % 8u / 4)
&& !(retaddr[6 * v3 - 6 + v6] % 2u)
&& !(retaddr[6 * v3 + 6 + v6] % 8u / 4)
&& !(retaddr[6 * v3 + 6 + v6] % 2u)

不能出现:当前节点为10 11 14 15,并且上一行为0 2 8 10,并且下一行为0 2 8 10的情况

约束3

   retaddr[6 * v3 + v6] % 8u / 4
&& retaddr[6 * v3 + v6] % 2u
&& !(retaddr[6 * v3 + 1 + v6] % 0x10u / 8)
&& !(retaddr[6 * v3 + 1 + v6] % 4u / 2)
&& !(retaddr[6 * v3 - 1 + v6] % 0x10u / 8)
&& !(retaddr[6 * v3 - 1 + v6] % 4u / 2)

不能出现:当前节点为5 7 13 15,并且上一列为0 1 4 5,下一列为0 1 4 5的情况

剩下的代码

last_x = 0;
last_y = 0;
now_x = 0;
now_y = 0;
if ( *retaddr % 0x10u / 8 )
{
    now_x = -1;
    while ( 1 )
    {
        LABEL_67:
        if ( !(retaddr[6 * now_x + now_y] % 0x10u / 8) || now_x - 1 == last_x && now_y == last_y ) // 当前为0-7或者上一步是向下走的,这一步就不能向上走
        {
            if ( !(retaddr[6 * now_x + now_y] % 4u / 2) || now_x + 1 == last_x && now_y == last_y ) // 当前为0 1 4 5 8 9 12 13或者上一步是向上走的,这一步就不能向下走
            {
                if ( !(retaddr[6 * now_x + now_y] % 8u / 4) || now_x == last_x && now_y - 1 == last_y ) // 当前为0 1 2 3 8 9 10 11或者上一步是向右走的,这一步就不能向左走
                {
                    if ( !(retaddr[6 * now_x + now_y] % 2u) || now_x == last_x && now_y + 1 == last_y ) // 当前为偶数或者上一步是向左走的,这一步就不能向右走
                        return MEMORY[0x1301](); // 没得走是不可能的
                    last_x = now_x;
                    last_y = now_y++; // 向右走
                }
                else
                {
                    last_x = now_x;
                    last_y = now_y--; // 向左走
                }
            }
            else
            {
                last_x = now_x;
                last_y = now_y;
                ++now_x; // 向下走
            }
        }
        else
        {
            last_x = now_x;
            last_y = now_y;
            --now_x; // 向上走
        }
        if ( !now_x && !now_y ) // 回到了(0,0)
            return MEMORY[0x1301](); // 这里应该是成功
    }
}
if ( *retaddr % 4u / 2 )
{
    now_x = 1;
    goto LABEL_67;
}
if ( *retaddr % 8u / 4 )
{
    now_y = -1;
    goto LABEL_67;
}
if ( *retaddr % 2u )
{
    now_y = 1;
    goto LABEL_67;
}
return MEMORY[0x1301]();

重命名了一些变量,方便理解

首先可以由所有的约束推出(0,0)是3,然后发现代码会进入到if ( *retaddr % 4u / 2 ),也就是说初值是当前位置是(1,0),上一位置是(0,0),然后手推吧

(注意7.(2)(3)的上下行、上下列是不同时为这些数,前面写的太省事了后面把自己推麻了。。)

那么得到flag:

d3ctf{22441442223133324424441111133333}

posted @ 2022-04-01 18:33  iPlayForSG  阅读(265)  评论(0)    收藏  举报