攻防世界新手专区——REVERSE

game

image-20220210123506016

打开附件看一下:

image-20220210124242313

可以看到是一个小游戏,输入一个数会改变这个数字及相邻两个数字对应的灯笼,

尝试一下很快就能通关,技巧在于把没亮的灯笼三个三个聚在一起,当在一起的灯笼数为3的倍数时自然过关。

image-20220210130220057

当然如果玩不了这个游戏也不影响我们做题。拿exeinfo查看一下。

image-20220210130851895

然后用IDA打开!

查看一下main函数:

void main_0()
{
  signed int i; // [esp+DCh] [ebp-20h]
  int v1; // [esp+F4h] [ebp-8h]

  sub_45A7BE(&unk_50B110);
  sub_45A7BE(&unk_50B158);
  sub_45A7BE(&unk_50B1A0);
  sub_45A7BE(&unk_50B1E8);
  sub_45A7BE(&unk_50B230);
  sub_45A7BE(&unk_50B278);
  sub_45A7BE(&unk_50B2C0);
  sub_45A7BE(&unk_50B308);
  sub_45A7BE(&unk_50AFD0);
  sub_45A7BE("|              by 0x61                                 |\n");
  sub_45A7BE("|                                                      |\n");
  sub_45A7BE("|------------------------------------------------------|\n");
  sub_45A7BE(
    "Play a game\n"
    "The n is the serial number of the lamp,and m is the state of the lamp\n"
    "If m of the Nth lamp is 1,it's on ,if not it's off\n"
    "At first all the lights were closed\n");
  sub_45A7BE("Now you can input n to change its state\n");
  sub_45A7BE(
    "But you should pay attention to one thing,if you change the state of the Nth lamp,the state of (N-1)th and (N+1)th w"
    "ill be changed too\n");
  sub_45A7BE("When all lamps are on,flag will appear\n");
  sub_45A7BE("Now,input n \n");
  while ( 1 )
  {
    while ( 1 )
    {
      sub_45A7BE("input n,n(1-8)\n");
      sub_459418();
      sub_45A7BE("n=");
      sub_4596D4("%d", &v1);
      sub_45A7BE("\n");
      if ( v1 >= 0 && v1 <= 8 )
        break;
      sub_45A7BE("sorry,n error,try again\n");
    }
    if ( v1 )
    {
      sub_4576D6(v1 - 1);
    }
    else
    {
      for ( i = 0; i < 8; ++i )
      {
        if ( (unsigned int)i >= 9 )
          j____report_rangecheckfailure();
        byte_532E28[i] = 0;
      }
    }
    j__system("CLS");
    sub_458054();
    if ( byte_532E28[0] == 1
      && byte_532E28[1] == 1
      && byte_532E28[2] == 1
      && byte_532E28[3] == 1
      && byte_532E28[4] == 1
      && byte_532E28[5] == 1
      && byte_532E28[6] == 1
      && byte_532E28[7] == 1 )
    {
      sub_457AB4();
    }
  }
}

很自然就可以想到这里的sub_457AB4就藏着本题的 flag ,我们我们跟进一下这个函数:

int sub_457AB4(void)
{
  return sub_45E940();
}
继续跟进可以看到这个函数是这样的(点击展开)

int sub_45E940()
{
signed int i; // [esp+D0h] [ebp-94h]
char v2; // [esp+DCh] [ebp-88h]
char v3; // [esp+DDh] [ebp-87h]
char v4; // [esp+DEh] [ebp-86h]
char v5; // [esp+DFh] [ebp-85h]
char v6; // [esp+E0h] [ebp-84h]
char v7; // [esp+E1h] [ebp-83h]
char v8; // [esp+E2h] [ebp-82h]
char v9; // [esp+E3h] [ebp-81h]
char v10; // [esp+E4h] [ebp-80h]
char v11; // [esp+E5h] [ebp-7Fh]
char v12; // [esp+E6h] [ebp-7Eh]
char v13; // [esp+E7h] [ebp-7Dh]
char v14; // [esp+E8h] [ebp-7Ch]
char v15; // [esp+E9h] [ebp-7Bh]
char v16; // [esp+EAh] [ebp-7Ah]
char v17; // [esp+EBh] [ebp-79h]
char v18; // [esp+ECh] [ebp-78h]
char v19; // [esp+EDh] [ebp-77h]
char v20; // [esp+EEh] [ebp-76h]
char v21; // [esp+EFh] [ebp-75h]
char v22; // [esp+F0h] [ebp-74h]
char v23; // [esp+F1h] [ebp-73h]
char v24; // [esp+F2h] [ebp-72h]
char v25; // [esp+F3h] [ebp-71h]
char v26; // [esp+F4h] [ebp-70h]
char v27; // [esp+F5h] [ebp-6Fh]
char v28; // [esp+F6h] [ebp-6Eh]
char v29; // [esp+F7h] [ebp-6Dh]
char v30; // [esp+F8h] [ebp-6Ch]
char v31; // [esp+F9h] [ebp-6Bh]
char v32; // [esp+FAh] [ebp-6Ah]
char v33; // [esp+FBh] [ebp-69h]
char v34; // [esp+FCh] [ebp-68h]
char v35; // [esp+FDh] [ebp-67h]
char v36; // [esp+FEh] [ebp-66h]
char v37; // [esp+FFh] [ebp-65h]
char v38; // [esp+100h] [ebp-64h]
char v39; // [esp+101h] [ebp-63h]
char v40; // [esp+102h] [ebp-62h]
char v41; // [esp+103h] [ebp-61h]
char v42; // [esp+104h] [ebp-60h]
char v43; // [esp+105h] [ebp-5Fh]
char v44; // [esp+106h] [ebp-5Eh]
char v45; // [esp+107h] [ebp-5Dh]
char v46; // [esp+108h] [ebp-5Ch]
char v47; // [esp+109h] [ebp-5Bh]
char v48; // [esp+10Ah] [ebp-5Ah]
char v49; // [esp+10Bh] [ebp-59h]
char v50; // [esp+10Ch] [ebp-58h]
char v51; // [esp+10Dh] [ebp-57h]
char v52; // [esp+10Eh] [ebp-56h]
char v53; // [esp+10Fh] [ebp-55h]
char v54; // [esp+110h] [ebp-54h]
char v55; // [esp+111h] [ebp-53h]
char v56; // [esp+112h] [ebp-52h]
char v57; // [esp+113h] [ebp-51h]
char v58; // [esp+114h] [ebp-50h]
char v59; // [esp+120h] [ebp-44h]
char v60; // [esp+121h] [ebp-43h]
char v61; // [esp+122h] [ebp-42h]
char v62; // [esp+123h] [ebp-41h]
char v63; // [esp+124h] [ebp-40h]
char v64; // [esp+125h] [ebp-3Fh]
char v65; // [esp+126h] [ebp-3Eh]
char v66; // [esp+127h] [ebp-3Dh]
char v67; // [esp+128h] [ebp-3Ch]
char v68; // [esp+129h] [ebp-3Bh]
char v69; // [esp+12Ah] [ebp-3Ah]
char v70; // [esp+12Bh] [ebp-39h]
char v71; // [esp+12Ch] [ebp-38h]
char v72; // [esp+12Dh] [ebp-37h]
char v73; // [esp+12Eh] [ebp-36h]
char v74; // [esp+12Fh] [ebp-35h]
char v75; // [esp+130h] [ebp-34h]
char v76; // [esp+131h] [ebp-33h]
char v77; // [esp+132h] [ebp-32h]
char v78; // [esp+133h] [ebp-31h]
char v79; // [esp+134h] [ebp-30h]
char v80; // [esp+135h] [ebp-2Fh]
char v81; // [esp+136h] [ebp-2Eh]
char v82; // [esp+137h] [ebp-2Dh]
char v83; // [esp+138h] [ebp-2Ch]
char v84; // [esp+139h] [ebp-2Bh]
char v85; // [esp+13Ah] [ebp-2Ah]
char v86; // [esp+13Bh] [ebp-29h]
char v87; // [esp+13Ch] [ebp-28h]
char v88; // [esp+13Dh] [ebp-27h]
char v89; // [esp+13Eh] [ebp-26h]
char v90; // [esp+13Fh] [ebp-25h]
char v91; // [esp+140h] [ebp-24h]
char v92; // [esp+141h] [ebp-23h]
char v93; // [esp+142h] [ebp-22h]
char v94; // [esp+143h] [ebp-21h]
char v95; // [esp+144h] [ebp-20h]
char v96; // [esp+145h] [ebp-1Fh]
char v97; // [esp+146h] [ebp-1Eh]
char v98; // [esp+147h] [ebp-1Dh]
char v99; // [esp+148h] [ebp-1Ch]
char v100; // [esp+149h] [ebp-1Bh]
char v101; // [esp+14Ah] [ebp-1Ah]
char v102; // [esp+14Bh] [ebp-19h]
char v103; // [esp+14Ch] [ebp-18h]
char v104; // [esp+14Dh] [ebp-17h]
char v105; // [esp+14Eh] [ebp-16h]
char v106; // [esp+14Fh] [ebp-15h]
char v107; // [esp+150h] [ebp-14h]
char v108; // [esp+151h] [ebp-13h]
char v109; // [esp+152h] [ebp-12h]
char v110; // [esp+153h] [ebp-11h]
char v111; // [esp+154h] [ebp-10h]
char v112; // [esp+155h] [ebp-Fh]
char v113; // [esp+156h] [ebp-Eh]
char v114; // [esp+157h] [ebp-Dh]
char v115; // [esp+158h] [ebp-Ch]
sub_45A7BE("done!!! the flag is ");
v59 = 18;
v60 = 64;
v61 = 98;
v62 = 5;
v63 = 2;
v64 = 4;
v65 = 6;
v66 = 3;
v67 = 6;
v68 = 48;
v69 = 49;
v70 = 65;
v71 = 32;
v72 = 12;
v73 = 48;
v74 = 65;
v75 = 31;
v76 = 78;
v77 = 62;
v78 = 32;
v79 = 49;
v80 = 32;
v81 = 1;
v82 = 57;
v83 = 96;
v84 = 3;
v85 = 21;
v86 = 9;
v87 = 4;
v88 = 62;
v89 = 3;
v90 = 5;
v91 = 4;
v92 = 1;
v93 = 2;
v94 = 3;
v95 = 44;
v96 = 65;
v97 = 78;
v98 = 32;
v99 = 16;
v100 = 97;
v101 = 54;
v102 = 16;
v103 = 44;
v104 = 52;
v105 = 32;
v106 = 64;
v107 = 89;
v108 = 45;
v109 = 32;
v110 = 65;
v111 = 15;
v112 = 34;
v113 = 18;
v114 = 16;
v115 = 0;
v2 = 123;
v3 = 32;
v4 = 18;
v5 = 98;
v6 = 119;
v7 = 108;
v8 = 65;
v9 = 41;
v10 = 124;
v11 = 80;
v12 = 125;
v13 = 38;
v14 = 124;
v15 = 111;
v16 = 74;
v17 = 49;
v18 = 83;
v19 = 108;
v20 = 94;
v21 = 108;
v22 = 84;
v23 = 6;
v24 = 96;
v25 = 83;
v26 = 44;
v27 = 121;
v28 = 104;
v29 = 110;
v30 = 32;
v31 = 95;
v32 = 117;
v33 = 101;
v34 = 99;
v35 = 123;
v36 = 127;
v37 = 119;
v38 = 96;
v39 = 48;
v40 = 107;
v41 = 71;
v42 = 92;
v43 = 29;
v44 = 81;
v45 = 107;
v46 = 90;
v47 = 85;
v48 = 64;
v49 = 12;
v50 = 43;
v51 = 76;
v52 = 86;
v53 = 13;
v54 = 114;
v55 = 1;
v56 = 117;
v57 = 126;
v58 = 0;
for ( i = 0; i < 56; ++i ) { *(&v2 + i) ^= *(&v59 + i); *(&v2 + i) ^= 0x13u; } return sub_45A7BE("%s\n"); }

发现函数进行了两次 xor 运算,xor 的逆运算也是 xor,那么我们就可以根据这个运算来写脚本得到最后的flag:

#exp.py
a=[18,64,98,5,2,4,6,3,6,48,49,65,32,12,48,65,31,78,62,32,49,32,1,57,96,3,21,9,4,62,3,5,4,1,2,3,44,65,78,32,16,97,54,16,44,52,32,64,89,45,32,65,15,34,18,16,0]
b=[123,32,18,98,119,108,65,41,124,80,125,38,124,111,74,49,83,108,94,108,84,6,96,83,44,121,104,110,32,95,117,101,99,123,127,119,96,48,107,71,92,29,81,107,90,85,64,12,43,76,86,13,114,1,117,126,0]
i=0
c=''
while (i<56):
    a[i]^=b[i]
    a[i]^=19
    c=c+chr(a[i])
    i=i+1
print (c)
#C:\Users\Administrator\Desktop
#λ python exp.py
#zsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}

当然这里直接 patch 程序,无条件调用 sub_457AB4()

open-source

image-20220211203509220

附件是一个c文件:

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    if (argc != 4) {
        printf("what?\n");
        exit(1);
    }

    unsigned int first = atoi(argv[1]);
    if (first != 0xcafe) {
        printf("you are wrong, sorry.\n");
        exit(2);
    }

    unsigned int second = atoi(argv[2]);
    if (second % 5 == 3 || second % 17 != 8) {
        printf("ha, you won't get it!\n");
        exit(3);
    }

    if (strcmp("h4cky0u", argv[3])) {
        printf("so close, dude!\n");
        exit(4);
    }

    printf("Brr wrrr grr\n");

    unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;

    printf("Get your key: ");
    printf("%x\n", hash);
    return 0;
}

用 gcc 编译一下,输出的是what?

这里报错了,显示少了个#include <stdlib.h>,加上就一切正常了!

观察一下这个c代码,发现需要提供三个参数:

  • ==0xcafe==

  • 25(满足 second % 5 = = 3 || second % 17 != 8

  • h4cky0u

Pwn@ubuntu:~/桌面$ ./a.out 51966 25 h4cky0u
Brr wrrr grr
Get your key: c0ffee

所以 flag 就是:c0ffee

==!不用加格式 !==

当然大佬们编写脚本的格式也足够优雅,这里仅引用一个 Hk_Mayfly 师傅的脚本:

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {

    int first = 0xcafe;
    int second = 25;
    argv[3] = "h4cky0u";

    printf("Brr wrrr grr\n");

    unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;

    printf("Get your key: ");
    printf("%x\n", hash);

    system("PAUSE");
    return 0;
}

simple-unpack

image-20220218232717192

打开Exeinfo PE,看一下相关信息:

image-20220218233100931

可以看到是64位的文件,且为UPX加壳。

一、IDA二进制打开

用二进制形式打开IDA,搜索字符串flag得到:

image-20220218234842075

二、UPX脱壳

先脱壳:

┌──(kali㉿kali)-[~/Desktop]
└─$ upx -d 847be14b3e724782b658f2dda2e8045b 
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2020
UPX 3.96        Markus Oberhumer, Laszlo Molnar & John Reiser   Jan 23rd 2020

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
    912808 <-    352624   38.63%   linux/amd64   847be14b3e724782b658f2dda2e8045b

Unpacked 1 file.

脱完壳再用IDA打开,先查看main函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s1; // [rsp+0h] [rbp-70h]
  unsigned __int64 v5; // [rsp+68h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  _isoc99_scanf((unsigned __int64)"%96s");
  if ( !strcmp(&s1, flag) )
    puts("Congratulations!", flag);
  else
    puts("Try again!", flag);
  return 0;
}

可以看到有flag,点击跟进一下,可以发现flag!

image-20220219000054721

logmein

image-20220219024629496

打开Exeinfo PE,查看基本信息:

image-20220219024745806

可以看到是64位的ELF文件,查看基础信息:

image-20220219025130696

用IDA打开,查看一下几个可疑的函数:

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  size_t v3; // rsi
  int i; // [rsp+3Ch] [rbp-54h]
  char s[36]; // [rsp+40h] [rbp-50h]
  int v6; // [rsp+64h] [rbp-2Ch]
  __int64 v7; // [rsp+68h] [rbp-28h]
  char v8[8]; // [rsp+70h] [rbp-20h]
  int v9; // [rsp+8Ch] [rbp-4h]

  v9 = 0;
  strcpy(v8, ":\"AL_RT^L*.?+6/46");
  v7 = 28537194573619560LL;
  v6 = 7;
  printf("Welcome to the RC3 secure password guesser.\n", a2, a3);
  printf("To continue, you must enter the correct password.\n");
  printf("Enter your guess: ");
  __isoc99_scanf("%32s", s);
  v3 = strlen(s);
  if ( v3 < strlen(v8) )
    sub_4007C0(v8);
  for ( i = 0; i < strlen(s); ++i )
  {
    if ( i >= strlen(v8) )
      ((void (*)(void))sub_4007C0)();
    if ( s[i] != (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]) )
      ((void (*)(void))sub_4007C0)();
  }
  sub_4007F0();
}
void __noreturn sub_4007C0()
{
  printf("Incorrect password!\n");
  exit(0);
}
void __noreturn sub_4007F0()
{
  printf("You entered the correct password!\nGreat job!\n");
  exit(0);
}

可以看出函数实现逻辑是要输入一个数字,等于经过处理的v7和v8的异或,v8很明显,但是v7不是很明确,上网查找一下,可以知道LL是长长整型,v7要转换为16进制然后在转换为字符串,而且字符是小端序,所以把得到的字符翻转然后和v8的每一位进行异或。这里借鉴大佬的脚本:

#wp.py
a = 'harambe'
b = ':\"AL_RT^L*.?+6/46'
print(b)
tmp = ''
for i in range(len(b)):
    c = ord(a[i % 7]) ^ ord(b[i])
    tmp += chr(c)
    print(tmp)
┌──(kali㉿kali)-[~/Desktop]
└─$ python wp.py 
:"AL_RT^L*.?+6/46
R
RC
RC3
RC3-
RC3-2
RC3-20
RC3-201
RC3-2016
RC3-2016-
RC3-2016-X
RC3-2016-XO
RC3-2016-XOR
RC3-2016-XORI
RC3-2016-XORIS
RC3-2016-XORISG
RC3-2016-XORISGU
RC3-2016-XORISGUD

得到flag:==RC3-2016-XORISGUD==

insanity

image-20220219003714917

首先还是查壳和程序的详细信息。

image-20220219003825660

可以看到是一个ELF的32位文件,打开虚拟机看一下相关信息:

image-20220219004321294

打开IDAF5查看一下伪函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  unsigned int v4; // eax

  puts("Reticulating splines, please wait..");
  sleep(5u);
  v3 = time(0);
  srand(v3);
  v4 = rand();
  puts((&strs)[v4 % 0xA]);
  return 0;
}

跟进一下发现一个关键的字符串,&strs,发现是取这个字符串输出,然后,跟进strs。猜测这个明显的就是最终 flag,试一下正确!这里也可以很自然想到打开string页面找到flag!

image-20220219005210595

flag就是==9447{This_is_a_flag}==

直接用文本形式打开文档,搜索flag字符也可以找到flag!

python-trade

image-20220219005945601

之前做过类似的题目,.pyc是py程序编译以后的字节码文件,需要用相应工具逆向,我使用的是uncompyle

安装==pip install uncompyle==

使用==uncompyle6 python-trade.pyc > python-trade.py==

得到的文件打开看一下:

I don't know about Python version '3.9.10' yet.
Python versions 3.9 and greater are not supported.
I don't know about Python version '3.9.10' yet.
Python versions 3.9 and greater are not supported.

。。。。。不支持。。。。好吧,之前也因为这个失败过,看一下之前的wp,好吧换一个版本在3.8及以下的python就行了。

C:\Users\Administrator\Desktop
λ uncompyle6 trade.pyc
# uncompyle6 version 3.8.0
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.8.10 (default, May 19 2021, 13:12:57) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: 1.py
# Compiled at: 2017-06-03 10:20:43
import base64
def encode(message):
    s = ''
    for i in message:
        x = ord(i) ^ 32
        x = x + 16
        s += chr(x)
    return base64.b64encode(s)
correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = ''
print 'Input flag:'
flag = raw_input()
if encode(flag) == correct:
    print 'correct'
else:
    print 'wrong'
# okay decompiling trade.pyc

观察可以看到flag加密以后可以得到字符串==XlNkVmtUI1MgXWBZXCFeKY+AaXNt==

写一个脚本反过来就行了。

#wp.py
import base64
def decode(message):
    s = ''
    imessage = base64.b64decode(message)
    for i in imessage:
        x = ord(i) - 16
        x = x ^ 32
        s += chr(x)
    return s
correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = decode(correct)
print(flag)

运行以后就可以得到:

┌──(kali㉿kali)-[~/Desktop]
└─$ python2 wp.py
nctf{d3c0mpil1n9_PyC}

re1

image-20220219142713515

附件是一个.exe文件:

image-20220219142816151

Exeinfo PE打开看一下:

image-20220219143039112

IDA 二进制打开

这个办法是网上师傅发的,太tm牛逼了:

查阅资料了解到,反编译的结果不是一定正确的,IDA采用递归下降法进行反编译,它的优点在于很少会在反编译时把数据当作代码来处理,不过这次IDA很明显把flag当成代码,进行了反编译,因此在string界面无法找到flag

解决方法是在IDA打开文件时选择binary file,在此模式下IDA不会进行反编译,此时再打开strings界面就可发现flag
——彬彬逊

image-20220219163728748

image-20220219163834308

懂了,按照大佬说的,以后每次都试试,嘿嘿。

使用vim打开,输入‘/’可进入查找模式也可以。

IDA

可以看到是一个32位的,用32位IDA打开看一下:

//main函数:
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  __int128 v5; // [esp+0h] [ebp-44h]
  __int64 v6; // [esp+10h] [ebp-34h]
  int v7; // [esp+18h] [ebp-2Ch]
  __int16 v8; // [esp+1Ch] [ebp-28h]
  char v9; // [esp+20h] [ebp-24h]

  _mm_storeu_si128((__m128i *)&v5, _mm_loadu_si128((const __m128i *)&xmmword_413E34));
  v7 = 0;
  v6 = qword_413E44;
  v8 = 0;
  printf(&byte_413E4C);
  printf(&byte_413E60);
  printf(&byte_413E80);
  scanf("%s", &v9);
  v3 = strcmp((const char *)&v5, &v9);
  if ( v3 )
    v3 = -(v3 < 0) | 1;
  if ( v3 )
    printf(aFlag);
  else
    printf((const char *)&unk_413E90);
  system("pause");
  return 0;
}

有个strcmp函数,比较 v5 和 v9 ,然后判断 v3,根据 v3 给出相应的结果,但是这里有一个 printf(aFlag) ,赶紧看一下:

image-20220219143922593

然而并没有得到 flag ,这个和上面那个输出是一样的,这么一看 flag 估计是 else 里的东西,打开看一下:

image-20220219165001100

这里有一个flag get,证明我们应该是找对了,但是找又找不到,没办法,只能查看条件了,v9 是输入项,v5 是给的,追踪一下 v5,没发现什么东西。

image-20220219165625539

没有东西,再看 main 函数,里面可看到:

image-20220219174400896

跟进一下xmmword_413E34:

image-20220219174553498

qword_413E44xmmword_413E34的数据拼起来用python把16进制的数转化成文本然后反向就可以写出 flag。

print ('7D4654435455443074656D30633165577B465443545544'.decode('hex'))
# 解码结果: }FTCTUD0tem0c1eW{FTCTUD

菜鸟-传奇师傅的wp里说点击xmmword再按a也可以转化成字符串也可以得到 flag。

image-20220219175046826

Hello, CTF

image-20220219175150467

先查看一下基本信息:

image-20220219175241559

image-20220219175320873

用IDA打开看一下,偷偷试了一下二进制打开,无果,哈哈哈。

//main函数
  signed int v3; // ebx
  char v4; // al
  int result; // eax
  int v6; // [esp+0h] [ebp-70h]
  int v7; // [esp+0h] [ebp-70h]
  char v8; // [esp+12h] [ebp-5Eh]
  char v9[20]; // [esp+14h] [ebp-5Ch]
  char v10; // [esp+28h] [ebp-48h]
  __int16 v11; // [esp+48h] [ebp-28h]
  char v12; // [esp+4Ah] [ebp-26h]
  char v13; // [esp+4Ch] [ebp-24h]

  strcpy(&v13, "437261636b4d654a757374466f7246756e");
  while ( 1 )
  {
    memset(&v10, 0, 0x20u);
    v11 = 0;
    v12 = 0;
    sub_40134B(aPleaseInputYou, v6);
    scanf(aS, v9);
    if ( strlen(v9) > 0x11 )
      break;
    v3 = 0;
    do
    {
      v4 = v9[v3];
      if ( !v4 )
        break;
      sprintf(&v8, asc_408044, v4);
      strcat(&v10, &v8);
      ++v3;
    }
    while ( v3 < 17 );
    if ( !strcmp(&v10, &v13) )
      sub_40134B(aSuccess, v7);
    else
      sub_40134B(aWrong, v7);
  }
  sub_40134B(aWrong, v7);
  result = stru_408090._cnt-- - 1;
  if ( stru_408090._cnt < 0 )
    return _filbuf(&stru_408090);
  ++stru_408090._ptr;
  return result;
}

可以看出:

  • 先是将字符串复制到v13的位置
  • 对输入进行了判断,输入的字符串不能大于17
  • 将字符串以十六进制输出,再将得到的十六进制字符添加到v10
  • 如果输入的字符串是否和v10的字符串相等,则得到真确的flag

image-20220219180611864

得到flag!

no-strings-attached

image-20220219202346085

查看一下程序基本信息,尝试运行:

image-20220219203534103

运行失败了,用IDA打开查看一下几个函数的伪代码。

//main()
int __cdecl main(int argc, const char **argv, const char **envp)
{
  setlocale(6, &locale);
  banner();
  prompt_authentication();
  authenticate();
  return 0;
}
//setlocale()
char *setlocale(int category, const char *locale)
{
  return setlocale(category, locale);
}
//bannner()
int banner()
{
  unsigned int v0; // eax
  v0 = time(0);
  srand(v0);
  wprintf(&unk_80488B0);
  rand();
  return wprintf(&unk_8048960);
}
//prompt_authentication()
int prompt_authentication()
{
  return wprintf(&unk_80489F8);
}
//authenticate()
void authenticate()
{
  wchar_t ws[8192]; // [esp+1Ch] [ebp-800Ch]
  wchar_t *s2; // [esp+801Ch] [ebp-Ch]

  s2 = (wchar_t *)decrypt(&s, &dword_8048A90);
  if ( fgetws(ws, 0x2000, stdin) )
  {
    ws[wcslen(ws) - 1] = 0;
    if ( !wcscmp(ws, s2) )
      wprintf(&unk_8048B44);
    else
      wprintf(&unk_8048BA4);
  }
  free(s2);
}

可以看到authenticate()比较重要,观察这个函数可以看到有一个decrypt的函数,将dword_8048A90给加密了,再往下看,将输入的 ws 值与 s2 进行对比,打印,可以分析得出 s2 就是 flag 。

本题需要动态调试。

image-20220513234634711

csaw2013reversing2

image-20220220113950597

查看基础信息:

image-20220220114035416

尝试运行,果然都是乱码。

image-20220220114112765

IDA打开:

//main()
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // ecx
  CHAR *lpMem; // [esp+8h] [ebp-Ch]
  HANDLE hHeap; // [esp+10h] [ebp-4h]

  hHeap = HeapCreate(0x40000u, 0, 0);
  lpMem = (CHAR *)HeapAlloc(hHeap, 8u, MaxCount + 1);
  memcpy_s(lpMem, MaxCount, &unk_409B10, MaxCount);
  if ( sub_40102A() || IsDebuggerPresent() )
  {
    __debugbreak();
    sub_401000(v3 + 4, lpMem);
    ExitProcess(0xFFFFFFFF);
  }
  MessageBoxA(0, lpMem + 1, "Flag", 2u);
  HeapFree(hHeap, 0, lpMem);
  HeapDestroy(hHeap);
  ExitProcess(0);
}

sub_40102A()IsDebuggerPresent() 的返回值为真,则执行调试断点指令 __debugbreak()sub_401000(v3 + 4, lpMem)ExitProcess(0xFFFFFFFF),否则执行 MessageBoxA(0, lpMem + 1, "Flag", 2u)

查看一下sub_40102A():

int sub_40102A()
{
  char v0; // t1

  v0 = *(_BYTE *)(*(_DWORD *)(__readfsdword(0x18u) + 48) + 2);
  return 0;
}

返回值恒为 0。

IsDebuggerPresent()是一个判断是否处于调试状态的库函数,若程序处于调试模式下,则返回值为非零;若未处于调试模式下,则返回值为零。

双击 sub_401000() 查看其反编译代码:

unsigned int __fastcall sub_401000(int a1, int a2)
{
  int v2; // esi
  unsigned int v3; // eax
  unsigned int v4; // ecx
  unsigned int result; // eax

  v2 = dword_409B38;
  v3 = a2 + 1 + strlen((const char *)(a2 + 1)) + 1;
  v4 = 0;
  result = ((v3 - (a2 + 2)) >> 2) + 1;
  if ( result )
  {
    do
      *(_DWORD *)(a2 + 4 * v4++) ^= v2;
    while ( v4 < result );
  }
  return result;
}

返回看汇编:

image-20220220121732196

int 3 中断即为调试断点指令,将光标置于中断指令所在行,依次点击 Edit -> Patch program -> Assemble,将其改为空指令 nop

重复上述操作,依次将 jmp short loc_4010EF 修改为 jmp short loc_4010B9,将 jz short loc_4010B9 修改为 jmp short loc_401096

image-20220220122321254

最后,依次点击 Edit -> Patch program -> Apply patches to input file… ,备份补丁程序。

再次执行,即可得到 flag!

image-20220220122512485

参考Secrypt Agency师傅的文章:【XCTF 攻防世界】 Reverse —— csaw2013reversing2

getit

image-20220220130946299

查看基本信息:

image-20220220131149152

IDA打开看一下:

//main()
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v3; // al
  __int64 v5; // [rsp+0h] [rbp-40h]
  int i; // [rsp+4h] [rbp-3Ch]
  FILE *stream; // [rsp+8h] [rbp-38h]
  char filename[8]; // [rsp+10h] [rbp-30h]
  unsigned __int64 v9; // [rsp+28h] [rbp-18h]

  v9 = __readfsqword(0x28u);
  LODWORD(v5) = 0;
  while ( (signed int)v5 < strlen(s) )
  {
    if ( v5 & 1 )
      v3 = 1;
    else
      v3 = -1;
    *(&t + (signed int)v5 + 10) = s[(signed int)v5] + v3;
    LODWORD(v5) = v5 + 1;
  }
  strcpy(filename, "/tmp/flag.txt");
  stream = fopen(filename, "w");
  fprintf(stream, "%s\n", u, v5);
  for ( i = 0; i < strlen(&t); ++i )
  {
    fseek(stream, p[i], 0);
    fputc(*(&t + p[i]), stream);
    fseek(stream, 0LL, 0);
    fprintf(stream, "%s\n", u);
  }
  fclose(stream);
  remove(filename);
  return 0;
}

看一下核心代码:

while ( (signed int)v5 < strlen(s) )
  {
    if ( v5 & 1 )
      v3 = 1;
    else
      v3 = -1;
    *(&t + (signed int)v5 + 10) = s[(signed int)v5] + v3;
    LODWORD(v5) = v5 + 1;                       
  }

image-20220220132813608

可以看到:

t=SharifCTF{????????????????????????????????}
s='c61b68366edeb7bdce3c6820314b7498'

重写上述代码,获得脚本:

#include <stdio.h>
#include <string.h>
int main()
{
    char s[]="c61b68366edeb7bdce3c6820314b7498";
    char t[]="SharifCTF{????????????????????????????????}";
    int v5=0;
    int v3=0;
    while(v5<strlen(s))
    {
        if(v5&1)
            v3=1;
        else
            v3=-1;
        t[v5+10]=s[v5]+v3;
        v5+=1;
    }
    printf("%s",t);
    return 0;
}

image-20220220133514410

得到 flag:==SharifCTF{b70c59275fcfa8aebf2d5911223c6589}==

maze

image-20220220133628618

查看基本信息:

image-20220220133920933

查看一下重要函数:

//main()
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  const char *v3; // rsi
  signed __int64 v4; // rbx
  signed int v5; // eax
  char v6; // bp
  char v7; // al
  const char *v8; // rdi
  __int64 v10; // [rsp+0h] [rbp-28h]

  v10 = 0LL;
  puts("Input flag:");
  scanf("%s", &s1, 0LL);
  if ( strlen(&s1) != 24 || (v3 = "nctf{", strncmp(&s1, "nctf{", 5uLL)) || *(&byte_6010BF + 24) != 125 )
  {
LABEL_22:
    puts("Wrong flag!");
    exit(-1);
  }
  v4 = 5LL;
  if ( strlen(&s1) - 1 > 5 )
  {
    while ( 1 )
    {
      v5 = *(&s1 + v4);
      v6 = 0;
      if ( v5 > 78 )
      {
        v5 = (unsigned __int8)v5;
        if ( (unsigned __int8)v5 == 79 )
        {
          v7 = sub_400650((char *)&v10 + 4, v3);
          goto LABEL_14;
        }
        if ( v5 == 111 )
        {
          v7 = sub_400660((char *)&v10 + 4, v3);
          goto LABEL_14;
        }
      }
      else
      {
        v5 = (unsigned __int8)v5;
        if ( (unsigned __int8)v5 == 46 )
        {
          v7 = sub_400670(&v10, v3);
          goto LABEL_14;
        }
        if ( v5 == 48 )
        {
          v7 = sub_400680(&v10, v3);
LABEL_14:
          v6 = v7;
          goto LABEL_15;
        }
      }
LABEL_15:
      v3 = (const char *)HIDWORD(v10);
      if ( !(unsigned __int8)sub_400690(asc_601060, HIDWORD(v10), (unsigned int)v10) )
        goto LABEL_22;
      if ( ++v4 >= strlen(&s1) - 1 )
      {
        if ( v6 )
          break;
LABEL_20:
        v8 = "Wrong flag!";
        goto LABEL_21;
      }
    }
  }
  if ( asc_601060[8 * (signed int)v10 + SHIDWORD(v10)] != 35 )
    goto LABEL_20;
  v8 = "Congratulations!";
LABEL_21:
  puts(v8);
  return 0LL;
}

可以看到四个函数:

bool __fastcall sub_400650(_DWORD *a1)//(_DWORD *)&v9 + 1 'O'
{
  int v1; // eax

  v1 = (*a1)--;
  return v1 > 0;
}
bool __fastcall sub_400660(int *a1)//(int *)&v9 + 1 'o'
{
  int v1; // eax

  v1 = *a1 + 1;
  *a1 = v1;
  return v1 < 8;
}
bool __fastcall sub_400670(_DWORD *a1)//&v9 '.'
{
  int v1; // eax

  v1 = (*a1)--;
  return v1 > 0;
}
bool __fastcall sub_400680(int *a1)//&v9 '0'
{
  int v1; // eax

  v1 = *a1 + 1;
  *a1 = v1;
  return v1 < 8;
}

根据二维数组的性质,可以判断出

  • O对应左
  • o对应右
  • .对应上
  • 0对应下

image-20220220134817151

看到这边有一段字符,将它按数组形式排列。

  ******
*   *  *
*** * **
**  * **
*  *#  *
** *** *
**     *
********

*是边界,空格是通路,#号是终点。

程序开头:

if ( strlen(&s1) != 24 || (v3 = "nctf{", strncmp(&s1, "nctf{", 5uLL)) || *(&byte_6010BF + 24) != 125 )

那么 flag 就应该是:==nctf{o0oo00O000oooo..OO}==

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇