game

打开附件看一下:

可以看到是一个小游戏,输入一个数会改变这个数字及相邻两个数字对应的灯笼,
尝试一下很快就能通关,技巧在于把没亮的灯笼三个三个聚在一起,当在一起的灯笼数为3的倍数时自然过关。

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

然后用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

附件是一个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

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

可以看到是64位的文件,且为UPX加壳。
一、IDA二进制打开
用二进制形式打开IDA,搜索字符串flag得到:

二、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!

logmein

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

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

用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

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

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

打开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!

flag就是==9447{This_is_a_flag}==
直接用文本形式打开文档,搜索flag字符也可以找到flag!
python-trade

之前做过类似的题目,.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

附件是一个.exe文件:

拿Exeinfo PE打开看一下:

IDA 二进制打开
这个办法是网上师傅发的,太tm牛逼了:
查阅资料了解到,反编译的结果不是一定正确的,IDA采用递归下降法进行反编译,它的优点在于很少会在反编译时把数据当作代码来处理,不过这次IDA很明显把flag当成代码,进行了反编译,因此在string界面无法找到flag
解决方法是在IDA打开文件时选择binary file,在此模式下IDA不会进行反编译,此时再打开strings界面就可发现flag
——彬彬逊


懂了,按照大佬说的,以后每次都试试,嘿嘿。
使用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) ,赶紧看一下:

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

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

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

跟进一下xmmword_413E34:

把qword_413E44和xmmword_413E34的数据拼起来用python把16进制的数转化成文本然后反向就可以写出 flag。
print ('7D4654435455443074656D30633165577B465443545544'.decode('hex'))
# 解码结果: }FTCTUD0tem0c1eW{FTCTUD菜鸟-传奇师傅的wp里说点击xmmword再按a也可以转化成字符串也可以得到 flag。

Hello, CTF

先查看一下基本信息:


用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

得到flag!
no-strings-attached

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

运行失败了,用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 。
本题需要动态调试。

csaw2013reversing2

查看基础信息:

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

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;
}返回看汇编:

int 3 中断即为调试断点指令,将光标置于中断指令所在行,依次点击 Edit -> Patch program -> Assemble,将其改为空指令 nop。
重复上述操作,依次将 jmp short loc_4010EF 修改为 jmp short loc_4010B9,将 jz short loc_4010B9 修改为 jmp short loc_401096

最后,依次点击 Edit -> Patch program -> Apply patches to input file… ,备份补丁程序。
再次执行,即可得到 flag!

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

查看基本信息:

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;                       
  }
可以看到:
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;
}

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

查看基本信息:

查看一下重要函数:
//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对应下

看到这边有一段字符,将它按数组形式排列。
  ******
*   *  *
*** * **
**  * **
*  *#  *
** *** *
**     *
*********是边界,空格是通路,#号是终点。
程序开头:
if ( strlen(&s1) != 24 || (v3 = "nctf{", strncmp(&s1, "nctf{", 5uLL)) || *(&byte_6010BF + 24) != 125 )那么 flag 就应该是:==nctf{o0oo00O000oooo..OO}==






