【MapleCTF2023】Rev - Writeup

# 初めに
どうも、クソ雑魚のなんちゃてエンジニアです。
本記事は __MapleCTF2023__ のRev問3題のWrtiteupとなります。

https://ctf2023.maplebacon.org/

3題だけ解けたので記載します。

# JaVieScript
以下のJavascript（とHTMLがあったがHTMLはあまり関係ない。）が渡されます。
```Javascript:
var flag = "maple{";
var honk = {};

async function hash(string) {
	const utf8 = new TextEncoder().encode(string);
	const hashBuffer = await crypto.subtle.digest('SHA-256', utf8);
	const hashArray = Array.from(new Uint8Array(hashBuffer));
	const hashHex = hashArray
	  .map((bytes) => bytes.toString(16).padStart(2, '0'))
	  .join('');
	return hashHex;
  }

async function constructflag() {
	const urlParams = new URLSearchParams(window.location.search);
	var fleg = "maple{";
	for (const pair of urlParams.entries()) {
		honk[pair[0]] = JSON.parse(pair[1]); 
	}

	if (honk.toString() === {}.toString()) {
		fleg += honk.toString()[9];
	}

	if (Object.keys(honk).length === 0) {
		const test = eval(honk.one);
		if (typeof test === 'number' && test * test + '' == test + '' && !/\d/.test(test)) {
			fleg += 'a' + test.toString()[0];
		}

		const quack = honk.two;

		if (quack.toString().length === 0 & quack.length === 1) {
			fleg += 'a' + (quack[0] + '')[0].repeat(4) + 'as';
		}

		const hiss = honk.three;

		if (hiss === "_are_a_mId_FruiT}") {
			fleg += hiss;
		}
	}
	if (await hash(fleg) == "bfe06d1e92942a0eca51881a879a0a9aef3fe75acaece04877eb0a26ceb8710d") {
		console.log(fleg);
	}
}

constructflag();
```
フラグを作成する挙動とそれがあっているかハッシュで突合する機能があります。
確認すると`maple{?a?a????as_are_a_mId_FruiT}`のようなフラグを作るようです。
後半の`????`は４つの同じ文字のリピートなので実質3変数です。
ハッシュ復号の解法よりはBruteForceでしょう。
`0xff`までの255までで以下の脳筋コードを書きます。
```Javascript
var flag = "maple{";
var honk = {};

async function hash(string) {
	const utf8 = new TextEncoder().encode(string);
	const hashBuffer = await crypto.subtle.digest('SHA-256', utf8);
	const hashArray = Array.from(new Uint8Array(hashBuffer));
	const hashHex = hashArray
	  .map((bytes) => bytes.toString(16).padStart(2, '0'))
	  .join('');
	return hashHex;
  }

async function constructflag() {
	const urlParams = new URLSearchParams(window.location.search);
	var fleg = "maple{";
	var fleg_mid = "a";
	var fleglast = "as_are_a_mId_FruiT}";

	for (const pair of urlParams.entries()) {
		honk[pair[0]] = JSON.parse(pair[1]); 
	}

	for (let i=0; i < 255; i++) {
		str1 = String.fromCharCode(i);
		fleg_tmp1 = fleg + str1 + fleg_mid

		for (let j = 0; j < 255; j++) {
			str2 = String.fromCharCode(j);
			fleg_tmp2 = fleg_tmp1 + str2 + fleg_mid

				for (let k = 0; k < 255; k++) {
					str3 = String.fromCharCode(k);
					str3 = str3.repeat(4);
					fleg_true = fleg_tmp2 + str3 + fleglast;

					if (await hash(fleg_true) == "bfe06d1e92942a0eca51881a879a0a9aef3fe75acaece04877eb0a26ceb8710d") {
						console.log(fleg_true);
						break;
					}
				}
		}
		console.log(i);
	}
	
	console.log('finished');
}

constructflag();
```
後は回すだけで1分かからないうちにフラグが現れます。
![スクリーンショット 2023-10-01 130009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/ade0a1bb-5a69-458a-5ca8-b0b8f38fb664.png)

# Actually Baby Rev
Revのベビー問かな？？
１つの実行ファイル`chal`が渡されます。実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/a51bb417-9a9c-3247-216d-c34dac11ef47.png)
何か入力を促されますが、Babyはそれが嫌いなようです。
Ghidraに食わせます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/ad2a1b60-848c-51ad-9ae9-03d1960b44d4.png)
```c
undefined8 FUN_00401996(void)

{
  int iVar1;
  undefined8 uVar2;
  
  FUN_00401953();
  puts("This baby does NOT stop crying. Please help I don\'t know what it wants!");
  puts("Maybe we should try to make it happy");
  printf("> ");
  iVar1 = FUN_00401524();
  if (iVar1 == 1) {
    puts("I don\'t think that the baby wants to play...");
    puts("Try something else, maybe it\'s hungry? ");
    printf("> ");
    iVar1 = FUN_00401632();
    if (iVar1 == 1) {
      puts("Okay, the baby is full. I can probably put it to sleep.");
      printf("> ");
      iVar1 = FUN_004017cd();
      if (iVar1 == 1) {
        printf("oops you forgot to burp the baby, the baby begins to burp: ");
        FUN_004011c6();
        puts(". What a strange choice of a baby\'s first word you wonder...");
        uVar2 = 0;
      }
      else {
        uVar2 = 0xffffffff;
      }
    }
    else {
      uVar2 = 0xffffffff;
    }
  }
  else {
    uVar2 = 0xffffffff;
  }
  return uVar2;
}

```
mainの関数です。シンボルは消されてますが、エントリーポイントからわかりますね。
まずは`FUN_00401524()`の関数の返り値で条件分岐してるのでこの関数をみます。
```c
undefined8 FUN_00401524(void)

{
  char *pcVar1;
  undefined8 uVar2;
  size_t sVar3;
  ushort **ppuVar4;
  int local_3c;
  char local_38 [40];
  int local_10;
  int local_c;
  
  pcVar1 = fgets(local_38,0x1e,stdin);
  if (pcVar1 == (char *)0x0) {
    uVar2 = 0xffffffff;
  }
  else {
    local_3c = 0;
    sVar3 = strcspn(local_38,"\n");
    local_38[sVar3] = '\0';
    for (local_c = 0; local_38[local_c] != '\0'; local_c = local_c + 1) {
      ppuVar4 = __ctype_b_loc();
      if (((*ppuVar4)[local_38[local_c]] & 0x800) == 0) {
        puts("The baby did not like that.");
        return 0xffffffff;
      }
      local_10 = local_38[local_c] + -0x30;
      if (local_10 == 5) {
        FUN_00401246(&local_3c);
      }
      else {
        if (local_10 != 9) {
          puts("The baby is now confused and is crying even louder...");
          return 0;
        }
        FUN_0040127d(&local_3c);
      }
    }
    if (local_3c == 0x7f) {
      uVar2 = 1;
    }
    else {
      uVar2 = 0;
    }
  }
  return uVar2;
}
```
以下の部分を確認すると入力値を１文字ずつ確認して数字かどうか判定しています。`& 0x800`は数字のビットマスクなので。またASCIIの数字の文字から数値を割り出すのに`-48`してます。
```c
    for (local_c = 0; local_38[local_c] != '\0'; local_c = local_c + 1) {
      ppuVar4 = __ctype_b_loc();
      if (((*ppuVar4)[local_38[local_c]] & 0x800) == 0) {
        puts("The baby did not like that.");
        return 0xffffffff;
      }
    local_10 = local_38[local_c] + -0x30;
```
続いて以下の奴。入力数値が`5`なら`FUN_00401246`を実施。`9`なら`FUN_0040127d`を実施し、それ以外の数字ならBabyが泣いちゃう。5または9の数字の羅列を投入して`local_3c`を`127`にすれば勝ちです。
```c
      if (local_10 == 5) {
        FUN_00401246(&local_3c);
      }
      else {
        if (local_10 != 9) {
          puts("The baby is now confused and is crying even louder...");
          return 0;
        }
        FUN_0040127d(&local_3c);
      }
    }
    if (local_3c == 0x7f) {
      uVar2 = 1;
    }
    else {
      uVar2 = 0;
    }
```
`FUN_00401246`を見ます。
```c
void FUN_00401246(int *param_1)

{
  printf("You started playing baby shark...");
  puts("The baby is hypnotized for a few seconds by the colors and starts crying again.");
  *param_1 = *param_1 + 5;
  return;
}
```
5のコマンドは`+5`であることが分かりました。続いて`FUN_0040127d`
```c
void FUN_0040127d(int *param_1)

{
  int local_14;
  int local_10;
  int local_c;
  
  printf("You hand the baby a cute squish toy in the shape of a cat...");
  puts("The baby flings it accross the room and starts crying again. ");
  *param_1 = *param_1 + 100;
  for (local_c = 0; local_c < 4; local_c = local_c + 1) {
    *param_1 = *param_1 + -4;
  }
  local_10 = 6;
  while (local_10 = local_10 + -1, local_10 != 0) {
    *param_1 = *param_1 + -9;
  }
  *param_1 = *param_1 + -0xf;
  local_14 = 2;
  do {
    *param_1 = *param_1 + -7;
    local_14 = local_14 + -1;
  } while (0 < local_14);
  *param_1 = *param_1 + -1;
  *param_1 = *param_1 + -1;
  *param_1 = *param_1 + -1;
  *param_1 = *param_1 + -1;
  *param_1 = *param_1 + -1;
  *param_1 = *param_1 + -1;
  return;
}
```
とても面倒なのですが、これしっかり流れを追うと`+4`となります。
よって以下の整数問題を解けば勝ちです。
```
5n+4m=127  #nは5の回数、mは9の回数
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/186dfc32-69de-c701-5d78-25e72e6656b3.png)
スタックの構成上、29文字までしか受け付けないので5のコマンドを多めにとって`55555555555555555555555999`を打ち込めばOK。
これで続いての項目が出現します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/7556461b-3149-d05e-5250-19069b26cebb.png)
次は`FUN_00401632`の判定に入ります。
```c
undefined8 FUN_00401632(void)

{
  char *pcVar1;
  undefined8 uVar2;
  size_t sVar3;
  ushort **ppuVar4;
  int local_1c;
  char local_16 [6];
  int local_10;
  int local_c;
  
  pcVar1 = fgets(local_16,6,stdin);
  if (pcVar1 == (char *)0x0) {
    uVar2 = 0xffffffff;
  }
  else {
    local_1c = 0;
    sVar3 = strcspn(local_16,"\n");
    local_16[sVar3] = '\0';
    for (local_c = 0; local_16[local_c] != '\0'; local_c = local_c + 1) {
      ppuVar4 = __ctype_b_loc();
      if (((*ppuVar4)[local_16[local_c]] & 0x800) == 0) {
        puts("The baby did not like that.");
        return 0xffffffff;
      }
      local_10 = local_16[local_c] + -0x30;
      if (local_10 == 4) {
        FUN_004013ba(&local_1c);
      }
      else {
        if (4 < local_10) {
LAB_00401726:
          puts("The baby is now confused and is crying even louder...");
          return 0;
        }
        if (local_10 == 1) {
          FUN_00401381();
          return 0;
        }
        if (local_10 != 2) goto LAB_00401726;
        FUN_00401392(&local_1c);
      }
    }
    if (((local_1c % 3 == 1) && (local_1c % 4 == 3)) && (local_1c % 5 == 1)) {
      uVar2 = 1;
    }
    else {
      uVar2 = 0;
    }
  }
  return uVar2;
}
```
似たようなもんですね。
今度はコマンド4と2です。（1はダミー関数へ、砂糖の取り過ぎには注意ですね）
同じように解析すると4は`+6`2は`+13`とわかります。
以下を解けば勝ちですね。
```
(6n+13m) mod 3 = 1 and
(6n+13m) mod 4 = 3 and
(6n+13m) mod 5 = 1       #nは4の回数、mは2の回数。
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/a311b1e8-cbc8-4d62-bfdd-773f92be87b5.png)
スタックの文字数制限から`4442`しか受け付けてくれません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/4d3fd2b3-7b7c-6cb4-518f-290ae3cfa80a.png)
最後に`FUN_004017cd`を確認します。この条件をクリアすればフラグです。
```c

undefined8 FUN_004017cd(void)

{
  int iVar1;
  char *pcVar2;
  undefined8 uVar3;
  size_t sVar4;
  ushort **ppuVar5;
  int local_1c;
  char local_16 [6];
  int local_10;
  int local_c;
  
  pcVar2 = fgets(local_16,6,stdin);
  if (pcVar2 == (char *)0x0) {
    uVar3 = 0xffffffff;
  }
  else {
    local_1c = 1;
    sVar4 = strcspn(local_16,"\n");
    local_16[sVar4] = '\0';
    for (local_c = 0; local_16[local_c] != '\0'; local_c = local_c + 1) {
      ppuVar5 = __ctype_b_loc();
      if (((*ppuVar5)[local_16[local_c]] & 0x800) == 0) {
        puts("The baby did not like that.");
        return 0xffffffff;
      }
      local_10 = local_16[local_c] + -0x30;
      switch(local_10) {
      case 0:
        iVar1 = FUN_00401418(&local_1c);
        if (iVar1 == 0) {
          return 0;
        }
        break;
      default:
        puts("The baby is now confused and is crying even louder...");
        return 0;
      case 3:
        iVar1 = FUN_004014e4(&local_1c);
        if (iVar1 == 0) {
          return 0;
        }
        break;
      case 6:
        iVar1 = FUN_0040145c(&local_1c);
        if (iVar1 == 0) {
          return 0;
        }
        break;
      case 7:
        iVar1 = FUN_0040149e(&local_1c);
        if (iVar1 == 0) {
          return 0;
        }
        break;
      case 8:
        iVar1 = FUN_004013f1(&local_1c);
        if (iVar1 == 0) {
          return 0;
        }
      }
    }
    if (local_1c == 0x906) {
      uVar3 = 1;
    }
    else {
      uVar3 = 0;
    }
  }
  return uVar3;
}
```
同じように0，3，6，7，8のコマンドがあります。
これらのコマンドの関数を解析すると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/4205c2f7-70fe-5bdf-990f-00674c1feb39.png)
8コマンドは3を生成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/66e08559-3778-35b0-b5f3-cb9e3db56227.png)
0コマンドは3の場合に7をかける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/e3101cc0-8761-ec8a-9bec-07cecac562d8.png)
6コマンドは21の場合に5をかける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/e87bbbb6-1ffd-3fb9-93c3-7824f73077d7.png)
7コマンドは105の場合に11をかける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/1081f3d1-fc08-492a-87d2-0b43547aa987.png)
3コマンドは1155の場合に2をかける。
これらのコマンドを使って`2310`にすればいいのでこの順番で実行し`80673`を入れる。これでフラグゲットだ。
これらのソルバーを書いた。
```python
from pwn import *

context.log_level = "debug"

binfile = './chal'
rhost = 'actually-baby-rev.ctf.maplebacon.org'
rport = 1337

gdb_script = '''
b main
'''

elf = ELF(binfile)
context.binary = elf

def conn():
    if args.REMOTE:
        p = remote(rhost, rport)
    elif args.GDB:
        p = process(elf.path)
        gdb.attach(p, gdbscript=gdb_script)
    else:
        p = process(elf.path)
    return p

p = conn()
p.recvuntil(b'>')
p.sendline(b'55555555555555555555555999')
p.recvuntil(b'>')
p.sendline(b'4442')
p.recvuntil(b'>')
p.sendline(b'80673')

print(p.recvrepeat().decode())
```
実行するとフラグが帰ってくる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/e1aefdfa-520c-68b9-987a-5d64c3058935.png)

# Tarpit
chalの実行ファイルが渡される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/a199634f-a4fc-78e9-abff-fcfdec485b97.png)
フラグ判定ファイルみたいだ。Ghidraに食わせる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/c587de6a-9009-f2fa-df08-1dd4c3a70fcc.png)
```c

undefined8 FUN_00101159(void)

{
  undefined uVar1;
  undefined4 uVar2;
  long lVar3;
  bool bVar4;
  byte bVar5;
  byte bVar6;
  long in_FS_OFFSET;
  byte local_55;
  undefined2 uStack_54;
  undefined uStack_52;
  undefined local_48 [16];
  undefined local_38 [16];
  undefined local_28 [16];
  undefined8 local_18;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  puts("Input Flag: ");
  local_48 = (undefined  [16])0x0;
  local_38 = (undefined  [16])0x0;
  local_28 = (undefined  [16])0x0;
  local_18 = 0;
  fgets(local_38,0x20,stdin);
  bVar4 = true;
  do {
    while( true ) {
      while( true ) {
        if (!bVar4) {
          if (local_48._8_8_ == 0x1f) {
            puts("Success");
          }
          else {
            puts("Failure");
          }
          if (local_10 == *(long *)(in_FS_OFFSET + 0x28)) {
            return 0;
          }
                    /* WARNING: Subroutine does not return */
          __stack_chk_fail();
        }
        lVar3 = (local_18 & 0xffff) * 5;
        uVar2 = *(undefined4 *)(&DAT_00104040 + lVar3);
        local_55 = (byte)uVar2;
        uStack_54 = (undefined2)((uint)uVar2 >> 8);
        uStack_52 = (undefined)((uint)uVar2 >> 0x18);
        uVar1 = (&DAT_00104044)[lVar3];
        bVar5 = local_55 >> 2;
        bVar6 = local_55 >> 1 & 1;
        if (bVar5 != 2) break;
        *(ulong *)(local_48 + (long)(int)(uint)bVar6 * 8) =
             (ulong)(byte)local_38[*(long *)(local_48 + (long)(int)(uint)(local_55 & 1) * 8)];
        local_18 = CONCAT62(local_18._2_6_,CONCAT11(uVar1,uStack_52));
      }
      if (bVar5 < 3) break;
LAB_001012b6:
      bVar4 = false;
    }
    if (bVar5 == 0) {
      *(long *)(local_48 + (long)(int)(uint)bVar6 * 8) =
           *(long *)(local_48 + (long)(int)(uint)bVar6 * 8) + 1;
      local_18 = CONCAT62(local_18._2_6_,CONCAT11(uVar1,uStack_52));
    }
    else {
      if (bVar5 != 1) goto LAB_001012b6;
      if (*(long *)(local_48 + (long)(int)(uint)bVar6 * 8) == 0) {
        local_18 = CONCAT62(local_18._2_6_,uStack_54);
      }
      else {
        *(long *)(local_48 + (long)(int)(uint)bVar6 * 8) =
             *(long *)(local_48 + (long)(int)(uint)bVar6 * 8) + -1;
        local_18 = CONCAT62(local_18._2_6_,CONCAT11(uVar1,uStack_52));
      }
    }
  } while( true );
}
```
なんのこっちゃ。
`dogbolt`に食わせてみる。

https://dogbolt.org/?id=31f968fe-d831-41ac-beed-489374f58a08#BinaryNinja=142&Ghidra=161

BinaryNinjaがまだ分かりやすい出力をしてくれた。流石スポンサー。
```c
int32_t main(int32_t argc, char** argv, char** envp)
{
    int32_t argc_1 = argc;
    char** argv_1 = argv;
    void* fsbase;
    int64_t rax = *(fsbase + 0x28);
    puts("Input Flag: ");
    int128_t s;
    __builtin_memset(&s, 0, 0x32);
    int128_t buf;
    fgets(&buf, 0x20, stdin);
    char i = 1;
    while (i != 0)
    {
        int16_t var_18_1;
        uint64_t rdx_1 = var_18_1;
        int32_t rdx_3 = *(&data_4040 + (rdx_1 * 5));
        char var_51_1 = *((rdx_1 * 5) + 0x4044);
        char rax_8 = ((rdx_3 >> 1) & 1);
        uint32_t rax_11 = (rdx_3 >> 2);
        if (rax_11 == 2)
        {
            *(&s + (rax_8 << 3)) = *(&buf + *(&s + ((rdx_3 & 1) << 3)));
            var_18_1 = *rdx_3[3];
        }
        else
        {
            if (rax_11 == 0)
            {
                uint32_t rax_12 = rax_8;
                *(&s + (rax_12 << 3)) = (*(&s + (rax_12 << 3)) + 1);
                var_18_1 = *rdx_3[3];
                continue;
            }
            else if (rax_11 == 1)
            {
                if (*(&s + (rax_8 << 3)) != 0)
                {
                    uint32_t rax_19 = rax_8;
                    *(&s + (rax_19 << 3)) = (*(&s + (rax_19 << 3)) - 1);
                    var_18_1 = *rdx_3[3];
                    continue;
                }
                else
                {
                    var_18_1 = *rdx_3[1];
                    continue;
                }
            }
            i = 0;
        }
    }
    if (*s[8] != 0x1f)
    {
        puts("Failure");
    }
    else
    {
        puts("Success");
    }
    *(fsbase + 0x28);
    if (rax == *(fsbase + 0x28))
    {
        return 0;
    }
    __stack_chk_fail();
    /* no return */
}
```
なんか`DAT_00104040`と`DAT_00104044`を取ってきて、そっから5バイト分取り出したりシフトしたりインクリメントやデクリメントしてナンチャラカンチャラしてフラグ判定してそうですね。
うん、何もわからん。
こういう時は動的にデバックしてみるに限る。その前にこのDATの出力を追っておく（レジストリ追ったときにわかりやすいので）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/de991e27-9eda-08b1-a973-0dbc3e74ef46.png)
0x2007104とか0x3007104とか連続したバイナリが入ってますね。
まぁ動かしてみます。GDBを使います。フラグは判定用に`maple{flag}`を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/b0a2d8a9-abb5-e2a8-ba77-7eff3d6fe2ed.png)
RAXに`DAT_00104040`が入ってきているのが分かります。
RDXには5バイト分取り出す命令の数字5バイトが来ます。これで`DAT_00104044`を取得できます。
取得した値はRDXに入ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/33ea4286-a036-e793-6996-ea81b82267a5.png)
RAXにはシフトした値が入っています。`1`ですね。これが条件分岐の判定の値になり`cmp eax`で比較されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/4f4549bf-372e-2474-7a93-70a782896922.png)
その後、最初に代入した`m`の文字は`l`に`sub rdx 01`でデクリメントされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/7abb0e6c-8e46-6db0-1640-f5468ad27568.png)
次に`5*2`のバイト`0xa`分のDATを引っ張り出します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/8adc109d-982f-0e85-e10b-9a95ad18e93e.png)
2週目のDATがRDXに入ってきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/261d0204-6f58-27e5-41c1-377a3f741542.png)
条件分岐はまた1に飛びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/78db01f5-d2c8-54f2-4cb1-99402d9ce92b.png)
`l`は`sub rdx 01`でデクリメントされ`k`になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/5342c585-295b-5044-cc76-c32f42ff7b82.png)
次の週もデクリメントされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/23c19f75-0f30-1ee0-2734-c3b871c6feb8.png)
`0x70`週目で0までシフトされた文字を消しに1の分岐へ飛びますが、デクリメントされません。
これは恐らく以下のコードの分岐でelseになっているからでしょう。
```c
if (*(&s + (rax_8 << 3)) != 0)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/762a1ce2-3b07-c5d2-7e07-6d14d0f73ae8.png)
次に2の分岐で何か保存してます、次の精査DATのポイントを指定しているのでしょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/01622224-76b1-2559-40d4-2c46dfed1bc8.png)
0の分岐の後（インクリメント？）に次の文字の精査に入ります。

何となくわかりました。
この`DAT_00104044`～`DAT_001081a0`のバイト（ほぼバイナリ全部JAN）でデクリメントの数（何回デクリメントできる文字なのか）によって文字を判定しているなと考察できます。
ここら辺はエスパーしつつソルバーを組み立てます。

`DAT_00104044`～`DAT_001081a0`のバイトを抽出してPythonでコードを書きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/fadd981f-52d3-6c18-246b-b55563f48878.png)
実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/03e9c352-3a2b-7220-5d5d-f6529d15d307.png)
ん？うまくいかない。
よくよく見てみると、各文字でLoop回数分文字がデクリメントされていることが分かります。
以下に修正コードを記載します。
```python
from pwn import *

raws = [0x04,0x71,0x00,0x02,0x00,0x04,0x71,0x00,0x03,0x00,.........] #自分で埋めてね


num = 0
st = 0
out = 0
flag=[]
while((num+1)*5<=len(raws)):
    tmp = raws[num*5:(num+1)*5]
    rdx_3 = b"".join([p8(x) for x in tmp])
    rax_11 = bytes([(byte >> 2) & 0xFF for byte in rdx_3])[0]
    
    if rax_11 == 1:
        st += 1
    elif rax_11 == 2:
        flag.append(chr(st+out))
        print(chr(st+out))
        out += 1
        st = 0
    elif rax_11 == 0:
        st += -1
    else:
        break
      
    if (num+1)*5> len(raws):
        break
      
    num += 1
      
print("".join(flag))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/c43a6632-b75d-5d14-b14b-12b9c7269852.png)
実行するとフラグをゲットできます。

# まとめ
難しかったです。
Reversingは根性ですね。
楽しかったです。ありがとうございました。