目录标题

  • 一、解压缩
  • 二、查看文件
  • 三、分析程序
  • 四、程序主要逻辑:
  • 五、逆向思路:
    • 步骤一:
    • 步骤二:
  • 六、解密代码:

题目提供了两个文件flag.tar和libarchive.dylib

一、解压缩

  flag.tar是一个不能直接在windwos下解压缩的文件,直接用tar -xvf flag.tar命令解压缩:

  提示不是一个tar压缩文件,但是其中包含了一个flag.txt的文件头,解压缩出了一个flag.txt文件。
  再用file flag.tar命令来查看文件的格式:

  是一个POSIX格式的tar压缩包
关于POSIX格式:
1、压缩
  如果你使用的是GNU tar,那么就有个参数来设置所产生的文件的格式:
-H, --format=FORMAT 创建指定格式的归档
  FORMAT 是以下格式中的一种:

gnu GNU tar 1.13.x 格式
oldgnu GNU 格式 as per tar <= 1.12
pax POSIX 1003.1-2001 (pax) 格式
posix 等同于 pax
ustar POSIX 1003.1-1988 (ustar) 格式
v7 old V7 tar 格式

  所以假如你要把flag目录打包成 posix格式的tar包,就可以用

tar -cf flag.tar --format=posix flag

或者是

tar -cf flag.tar -H posix flag

2、解压:

tar -xvf flag.tar -H posix

二、查看文件

  继续回到题目,打开flag.txt:

  每4个16进制数字一组,以逗号分割,应该是另一个文件libarchive.dylib使用的输入或者输出文件,查看libarchive.dylib的格式:

  是Mac平台下的64位动态链接共享库
  用IDA64打开:

三、分析程序

  根据flag.txt文件的格式,输入输出的时候应该是使用了格式化字符串的%04x、%04X之类的把数据格式化,直接在IDA字符串窗口中搜索%04x、%04X:

  找到按%04X输出的位置,__int64 __fastcall archive_write_client_write(__int64 a1, __int64 a2, unsigned __int64 a3)函数:

函数原型:

int __sprintf_chk (char *s, int flags, size_t len, const char *format, ...)
__sprintf_chk(&v9[v3], 0, 0xFFFFFFFFFFFFFFFFLL, "%04X,", sub_101[v8++]);

  把sub_101[v8++]根据格式字符串"%04X,",将格式化输出写入&v9[v3]
函数原型:

void * __memcpy_chk (void *dest, const void *src, size_t len, size_t dstlen)
__memcpy_chk(v10, v9, v18, -1LL);

  把v9的值复制给v10
  所以我们接下来看一下sub_101数组的值是怎么来的,选中sub_101右键Jump to xrefs或者快捷键X查看使用到sub_101数组的地方:

  第二次就是在这个archive_write_client_write函数中,点击第一次使用sub_101数组的地方应该就是生成它的值的地方:

  posi是一个全局变量的数组下标,这个sub_1023458函数每次由输入*a1计算得到一个sub_101[posi]的值。
  再找到上一个调用sub_1023458函数的地方:
sub_1023456(int a1)函数:

  果然sub_1023457函数就是在循环中每次调用sub_1023456函数根据输入的字符返回不同的下标返回值,作为sub_1023458函数的参数,调用sub_1023458函数给sub_101数组赋值。
sub_1023456(int a1)函数:

  sub_1023458函数的实际参数v9数组有3个元素,刚好对应上面sub_1023458函数的*a1、a1[1]、a1[2]。
  再找到调用sub_1023457函数的地方,发现就是archive_write_client_write函数:

四、程序主要逻辑:

  所以现在的程序主要逻辑就是在archive_write_client_write函数中,流程图:

1、 首先archive_write_client_write函数第25行:
__memcpy_chk(v13, a2, a3, -1LL);
从输入的字符串a2中复制字符串的长度a3个字节到v13;

2、之后当字符串的长度a3>0x200时,调用sub_1023457(v13, (unsigned int)a3);对输入的字符串v13进行计算;

3、sub_1023456(v5)判断输入的字符串的每个字符,是否属于ctable[]数组,根据不同情况置pending标志位,然后设置返回值返回;

4、每执行3次v9[–v6] = sub_1023456(v5),重置了新的v9[3]数组的3个值,就执行一次sub_1023458(v9),sub_1023458函数中主要是计算得到一个sub_101[v2] = *a1 + 40 * a1[1] + 1600 * a1[2]的值;

5、计算结束之后,返回到archive_write_client_write函数:
__sprintf_chk(&__s[v3], 0, 0xFFFFFFFFFFFFFFFFLL, “%04X,”, sub_101[v11++]);
就会把sub_101[v8++]根据格式字符串"%04X,",将格式化输出写入&v9[v3]。

五、逆向思路:

所以我们现在是相当于知道了最后的结果sub_101,要得到最开始的输入v13。

步骤一:

1、首先是sub_1023458函数中解sub_101[v2] = a1 + 40 * a1[1] + 1600 * a1[2]这个三元一次方程组,每个sub_101[v2]的值都可以计算得到一组v9数组的值a1、a1[1]、a1[2]:

*a1=sub_101[v2] % 40;
a1[1]=(sub_101[v2] / 40) % 40;
a1[2]=sub_101[v2] / 1600;

步骤二:

2、之后每一组v9数组的值都对应1个sub_1023456函数输入的字符,也就是根据函数返回值(ctable数组下标),找到输入的字符(ctable数组下标对应的字符)。sub_1023457函数调用sub_1023456(v5)给v9数组的3个数赋值之后,再调用sub_1023458函数。
(1)sub_1023456(v5)函数原理是判断输入的字符,如果属于ctable数组前39个,pending 置0,直接返回对应的ctable数组下标i,并且返回之后会退出给v9[1]赋值的循环;
(2)如果如果属于ctable数组后39个(i+39),就返回39,且下一次的返回值就是i;如果不属于ctable数组就返回37。
  所以我们在知道返回值的时候,要逆推得到输入的字符,就要分为返回值是39也就是属于后39个字符的情况和返回值是小于39也就是属于前39个字符的两种情况。
  这里我们为了方便理解sub_1023457和sub_1023456函数的作用我们直接用C语言复现了它的逻辑:

#include<stdio.h>
#include<stdbool.h>bool pending;
int sub_1023456_shifted = -1;
int ctable[] = {0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73,
0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x20, 0x0A, 0x00,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x28, 0x21, 0x40, 0x23,
0x2C, 0x2E, 0x3F, 0x2F, 0x2A, 0x29, 0x3C, 0x3E, 0x00};int main()
{char * v3; // raxunsigned int v5; // [rsp+4h] [rbp-2Ch]int v6; // [rsp+8h] [rbp-28h]int v9[3]; // [rsp+1Ch] [rbp-14h] BYREFchar a1[] = "abcABc";//定义一个字符数组int length = sizeof(a1);int i;v6 = 3;v3 = a1;          // 输入的字符串while ( v3-a1 < length ){v5 = *v3++;//printf("%c ",v5);pending = 1;                                // 这是一个全局bool变量pending,在sub_1023456(v5)中也有改变它的值while ( pending ){v9[--v6] = sub_1023456(v5);               // v9[2]、v9[1]、v9[0]=,一个字符v5最多可以得到3个不同的返回值//printf("%d ",v9[v6]);if ( !v6 )                                // v6=0时执行{for(i = 0 ; i<3; i++){printf("%d ",v9[i]);}printf("\n");//sub_1023458(v9);                        // v9数组每得到3个值就调用sub_1023458函数给sub_101数组赋一个值v6 = 3;                                 // 重新赋值为3}}}if ( v6 != 3 )                                // 如果上面v9数组没有全部赋值,剩下的补足0后继续调用sub_1023458函数给sub_101数组赋最后一个值{while ( v6 != -1 )v9[--v6] = 0;for(i = 0 ; i<3; i++){printf("%d ",v9[i]);}printf("\n");//sub_1023458(v9);}return 0;
}int sub_1023456(int a1)
{int v2; // [rsp+0h] [rbp-Ch]int i; // [rsp+0h] [rbp-Ch]int v4; // [rsp+4h] [rbp-8h]unsigned int v5; // [rsp+8h] [rbp-4h]v4 = a1;                                      // 输入的字符if ( sub_1023456_shifted == -1 ){if ( a1 == 126 )                            // ASCII值等于126(‘~’)v4 = 0;for ( i = 0; i < 39; ++i ){if ( ctable[i] == v4 )                    // ctable数组前39个包括小写字母和数字,如果v4在这里面{pending = 0;                            // pending 置0,会退出给v9赋值的循环return (unsigned int)i;                 // 就返回下标}if ( ctable[i + 39] == v4 )               // ctable数组后39个包括大写字母和符号,如果v4在这里面{pending = 1;                            // pending 置1,会继续给v9[1]赋值sub_1023456_shifted = i;                // 这个值改为当前i,下次调用的时候就会执行else部分return 39;                              // 返回39,下一次的返回值就直接为这次的i}}pending = 0;                                // 如果v4的值不在数组里v5 = 37;                                    // ctable[37]是空格}else{v2 = sub_1023456_shifted;                   // 获得上一次执行返回的isub_1023456_shifted = -1;                   // 值重新置为-1,下次又执行if部分pending = 0;                                // pending 置0v5 = v2;}return v5;                                    // 返回上一次执行的i
}

运行结果:

  可以看到当输入的字符串是:"abcABc"时,对应的输出是:
3 2 1
39 1 39
0 3 2
其中字符’a’在ctable数组中的下标是1,所以返回值是1赋值给v9[2];
其中字符’b’在ctable数组中的下标是2,所以返回值是2赋值给v9[1];
其中字符’c’在ctable数组中的下标是3,所以返回值是3赋值给v9[0];
字符’A’在ctable数组中的下标是40,所以返回值是39赋值给v9[2],以及下一次的返回值是1赋值给v9[1];
字符’B’在ctable数组中的下标是41,所以返回值是39赋值给v9[0],以及下一次的返回值是2赋值给v9[2];
其中字符’c’在ctable数组中的下标是3,所以返回值是3赋值给v9[1];
最后这次v9[0]没有被赋值,所以最后补0。

六、解密代码:

  到这,我们就完全明白了加密的流程和逆向的思路,接下来用Python编写解密代码:

# py -3
# -*- coding: utf-8 -*-
# coding:utf-8# 最后flag.txt中的密文
ciphertext=[0xF5D1,0x4D6B,0xED6A,0x08A6,0x38DD,0xF7FA,0x609E,0xEBC4,0xE55F,0xE6D1,0x7C89,0xED5B,0x0871,0x1A69,0x5D58,0x72DE,0x224B,0x3AA6,0x0845,0x7DD6,0x58FB,0xE9CC,0x0A2D,0x76B8,0xED60,0x251A,0x1F6B,0x32CC,0xE78D,0x12FA,0x201A,0xE889,0x2D25,0x922A,0x4BC5,0xF5FF,0xF8E5,0xC79B,0x3A77,0x4BDB,0xEA11,0x5941,0x58BD,0x3A95,0xF5C9,0xA225,0xAD40,0xF8BD,0x095D,0x70B6,0x458C,0xE7A9,0xEA68,0x252F,0x094B,0x5E41,0x0969,0x6015,0x5ED5,0xF6E5,0x59B9,0x7CAF,0x66DF,0x265B,0x7837,0x57B4,0x7CAF,0xAED9,0xF707,0x6A3C,0xF8E5,0xF509,0x7C8B,0x0915,0x2235,0x336F,0x33E9,0x2D14,0x7C91,0x5804,0x83E5,0xE78D,0xF4EA,0x0874,0xED6B,0x4B35,0xE839,0x57B4,0xE77C,0xEA68,0x2525,0xAD41,0xED6F,0x3A4A,0x4BCC,0x6015,0xF440,0x0858,0x3AA6,0x7809,0x671D,0x0874,0xEA77,0x63AF,0x2E91,0x5845,0xF6C4,0x086D,0x7795,0x3939,0x57B4,0x7C89,0x82DC,0x32ED,0xB994,0xC7AF,0x9135,0x0E65,0x1B66,0xED5B,0x3235,0x6577,0x5A80,0x3AD3,0xE776,0x1EE5,0xAD41,0xED59,0x864C,0x70B4,0x3876,0xED67,0x64D6,0xF8E5,0xF505,0xEAD9,0x7C9C,0x32ED,0xB994,0xB4EF,0x0C6C,0xF665,0xF5F5,0x9047,0x521A,0xE99E,0xEA68,0x252F,0x9D09,0x76B7,0xE776,0x1ED0,0x095D,0x0D4D,0x5D5A,0x087B,0x2005,0x1526,0x7E76,0x85AD,0x78B9,0xE8B6,0x782C,0x251C,0x32ED,0x7F68,0xEBE3,0xEA41,0x57FD,0xED59,0x846D,0x7A05,0xB994,0xBB78,0xED6A,0x08A6,0x38DD,0x3B5D,0x7E45,0xE839,0x738C,0xE9CC,0x0A2D,0x764A,0x609E,0xE8B6,0xEA68,0x2524,0xE6BB,0x7C9C,0x639F,0x3A95,0x0895,0xF40F,0x8328,0xEA69,0x7EE5,0xF8BD,0x7F7D,0x0D6D,0x70B6,0x458C,0xE8B6,0xEA68,0x251C,0x6065,0xB35F,0xC789,0x5845,0x7F7D,0x6D89,0x4C6E,0xA20E,0x60B5,0x7E45,0xED59,0xF707,0x69EF,0x922A,0x4BC5,0xF6EF,0x8635,0xF4B9,0x57B4,0x7CF8,0xED60,0x2510,0x095D,0x20AF,0x3545,0xF40F,0x8328,0xEA41,0x58A4,0x225D,0x7E7C,0x4BDB,0xF8BD,0x082C,0xEAE7,0x5D57,0x5D50,0x0914,0xE7C7,0x8624,0x7CF8,0xED60,0x2511,0x7C8E,0x7159,0x8416,0x7EF9,0xE7E5,0x774A,0x3895,0x1EC9,0x7C90,0x09B9,0x58BD,0x5FF5,0xE99E,0xEA68,0x250A,0x224C,0xEA3D,0x73F5,0x7C89,0x53A6,0x3190,0x3B5D,0x1526,0x7DD5,0x666A,0x0919,0x225F,0xCDEF,0x79E1,0x7E7B,0x7E6B,0x082C,0xA277,0xE885,0xE8BB,0xE775,0x5FF7,0xEA68,0x251B,0x7FDF,0x589D,0x7A05,0x779A,0x8A5A,0x7C91,0x5D5C,0x32ED,0xF628,0x2195,0xF49A,0x0C77,0xEAE1,0x59B9,0x58BD,0xE570,0xE99E,0xEA3D,0x73F9,0x13AD,0x2BF5,0x225D,0x7F7D,0x70B6,0x4A9C,0x337A,0x1EC9,0x4D05,0x7E75,0x2578,0xED59,0x38E5,0x1ECA,0xA210,0x3B5D,0x779A,0x8A6F,0xC790,0x2518,0x4B41,0x7C89,0x5D49,0x4D05,0x152D,0x73C5,0x79F9,0x4BED,0x913C,0x37C9,0x5D4D,0x53C8,0x0941,0x7C97,0x5D5B,0x346A,0x82D8,0x5F36,0x801F,0xC800]
# 所有的v9数组
v9 = []
# 每个v9数组逆推得到的字符下标数组
v5 = []
# 输入的flag
flag = ""
# ctable字符常量数组
ctable = [
0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73,
0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x20, 0x0A, 0x00,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x28, 0x21, 0x40, 0x23,
0x2C, 0x2E, 0x3F, 0x2F, 0x2A, 0x29, 0x3C, 0x3E, 0x00]## 1、解3元一次方程,得到a0、a1、a2一组三个数
for cipher in ciphertext:a0 = cipher%40a1 = (cipher//40)%40a2 = cipher//1600v9 += [a2,a1,a0]# 2、v9数组中的数可以得到字符下标
i=0
while i < len(v9):# 数字等于39,加上下一个数,组成一个后40个字符的下标if v9[i] == 39:v5 += [v9[i]+v9[i+1]]i += 2# 数字在39以内的直接当前成前40个字符的下标else :v5 += [v9[i]]i += 1# 每个字符下标都对应一个字符,这时候字符下标数组里
for lab in v5:# 去掉最后填一堆的0if ctable[lab] != 0x0:flag += chr(ctable[lab])
print(flag)

运行结果:

  得到这段文本:

Milos Raonic (born 1990) is a Canadian professional tennis player. He reached a career high world No. 4 singles ranking in May 2015, as ranked by the Association of Tennis Professionals (ATP). His career highlights include a Grand Slam final at the 2016 Wimbledon Championships and two Grand Slam semifinals at the 2014 Wimbledon Championships and 2016 Australian Open. He was the 2011 ATP Newcomer of the Year, and has been ranked continuously inside the top 20 since August 2012. Raonic is the first player born in the 1990s to win an ATP title, to be ranked in the top 10, and to qualify for the ATP World Tour Finals. He has eight ATP singles titles, all won on hard courts. He is frequently described as having one of the best serves among his contemporaries. Statistically, he is among the strongest servers in the Open Era, winning 91p of service games to rank third all time. Aided by his serve, he plays an all court style with an emphasis on short points.

  它的MD5值:2c8cd31daeba8753815851f13e6370b3
  但是代码在windwos下的PyCharm客户端执行的时候需要加一个换行,因为在linux终端输出的时候它是自带了一个换行,但是在这我们要给它加上,不然md5值就会不一样:

# py -3
# -*- coding: utf-8 -*-
# coding:utf-8from hashlib import md5# 最后flag.txt中的密文
ciphertext=[0xF5D1,0x4D6B,0xED6A,0x08A6,0x38DD,0xF7FA,0x609E,0xEBC4,0xE55F,0xE6D1,0x7C89,0xED5B,0x0871,0x1A69,0x5D58,0x72DE,0x224B,0x3AA6,0x0845,0x7DD6,0x58FB,0xE9CC,0x0A2D,0x76B8,0xED60,0x251A,0x1F6B,0x32CC,0xE78D,0x12FA,0x201A,0xE889,0x2D25,0x922A,0x4BC5,0xF5FF,0xF8E5,0xC79B,0x3A77,0x4BDB,0xEA11,0x5941,0x58BD,0x3A95,0xF5C9,0xA225,0xAD40,0xF8BD,0x095D,0x70B6,0x458C,0xE7A9,0xEA68,0x252F,0x094B,0x5E41,0x0969,0x6015,0x5ED5,0xF6E5,0x59B9,0x7CAF,0x66DF,0x265B,0x7837,0x57B4,0x7CAF,0xAED9,0xF707,0x6A3C,0xF8E5,0xF509,0x7C8B,0x0915,0x2235,0x336F,0x33E9,0x2D14,0x7C91,0x5804,0x83E5,0xE78D,0xF4EA,0x0874,0xED6B,0x4B35,0xE839,0x57B4,0xE77C,0xEA68,0x2525,0xAD41,0xED6F,0x3A4A,0x4BCC,0x6015,0xF440,0x0858,0x3AA6,0x7809,0x671D,0x0874,0xEA77,0x63AF,0x2E91,0x5845,0xF6C4,0x086D,0x7795,0x3939,0x57B4,0x7C89,0x82DC,0x32ED,0xB994,0xC7AF,0x9135,0x0E65,0x1B66,0xED5B,0x3235,0x6577,0x5A80,0x3AD3,0xE776,0x1EE5,0xAD41,0xED59,0x864C,0x70B4,0x3876,0xED67,0x64D6,0xF8E5,0xF505,0xEAD9,0x7C9C,0x32ED,0xB994,0xB4EF,0x0C6C,0xF665,0xF5F5,0x9047,0x521A,0xE99E,0xEA68,0x252F,0x9D09,0x76B7,0xE776,0x1ED0,0x095D,0x0D4D,0x5D5A,0x087B,0x2005,0x1526,0x7E76,0x85AD,0x78B9,0xE8B6,0x782C,0x251C,0x32ED,0x7F68,0xEBE3,0xEA41,0x57FD,0xED59,0x846D,0x7A05,0xB994,0xBB78,0xED6A,0x08A6,0x38DD,0x3B5D,0x7E45,0xE839,0x738C,0xE9CC,0x0A2D,0x764A,0x609E,0xE8B6,0xEA68,0x2524,0xE6BB,0x7C9C,0x639F,0x3A95,0x0895,0xF40F,0x8328,0xEA69,0x7EE5,0xF8BD,0x7F7D,0x0D6D,0x70B6,0x458C,0xE8B6,0xEA68,0x251C,0x6065,0xB35F,0xC789,0x5845,0x7F7D,0x6D89,0x4C6E,0xA20E,0x60B5,0x7E45,0xED59,0xF707,0x69EF,0x922A,0x4BC5,0xF6EF,0x8635,0xF4B9,0x57B4,0x7CF8,0xED60,0x2510,0x095D,0x20AF,0x3545,0xF40F,0x8328,0xEA41,0x58A4,0x225D,0x7E7C,0x4BDB,0xF8BD,0x082C,0xEAE7,0x5D57,0x5D50,0x0914,0xE7C7,0x8624,0x7CF8,0xED60,0x2511,0x7C8E,0x7159,0x8416,0x7EF9,0xE7E5,0x774A,0x3895,0x1EC9,0x7C90,0x09B9,0x58BD,0x5FF5,0xE99E,0xEA68,0x250A,0x224C,0xEA3D,0x73F5,0x7C89,0x53A6,0x3190,0x3B5D,0x1526,0x7DD5,0x666A,0x0919,0x225F,0xCDEF,0x79E1,0x7E7B,0x7E6B,0x082C,0xA277,0xE885,0xE8BB,0xE775,0x5FF7,0xEA68,0x251B,0x7FDF,0x589D,0x7A05,0x779A,0x8A5A,0x7C91,0x5D5C,0x32ED,0xF628,0x2195,0xF49A,0x0C77,0xEAE1,0x59B9,0x58BD,0xE570,0xE99E,0xEA3D,0x73F9,0x13AD,0x2BF5,0x225D,0x7F7D,0x70B6,0x4A9C,0x337A,0x1EC9,0x4D05,0x7E75,0x2578,0xED59,0x38E5,0x1ECA,0xA210,0x3B5D,0x779A,0x8A6F,0xC790,0x2518,0x4B41,0x7C89,0x5D49,0x4D05,0x152D,0x73C5,0x79F9,0x4BED,0x913C,0x37C9,0x5D4D,0x53C8,0x0941,0x7C97,0x5D5B,0x346A,0x82D8,0x5F36,0x801F,0xC800]
# 所有的v9数组
v9 = []
# 每个v9数组逆推得到的字符下标数组
v5 = []
# 输入的flag
flag = ""
# ctable字符常量数组
ctable = [
0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73,
0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x20, 0x0A, 0x00,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x28, 0x21, 0x40, 0x23,
0x2C, 0x2E, 0x3F, 0x2F, 0x2A, 0x29, 0x3C, 0x3E, 0x00]## 1、解3元一次方程,得到a0、a1、a2一组三个数
for cipher in ciphertext:a0 = cipher%40a1 = (cipher//40)%40a2 = cipher//1600v9 += [a2,a1,a0]# 2、v9数组中的数可以得到字符下标
i=0
while i < len(v9):# 数字等于39,加上下一个数,组成一个后40个字符的下标if v9[i] == 39:v5 += [v9[i]+v9[i+1]]i += 2# 数字在39以内的直接当前成前40个字符的下标else :v5 += [v9[i]]i += 1# 每个字符下标都对应一个字符,这时候字符下标数组里
for lab in v5:# 去掉最后填一堆的0if ctable[lab] != 0x0:flag += chr(ctable[lab])
# 这段话最后还有一个换行
flag += '\n'
print(flag)
# 输出小写16进制的MD5值
print("md5值为:",md5(flag.encode()).hexdigest())

运行结果:

  也可以得到它的MD5值:2c8cd31daeba8753815851f13e6370b3

XCTF-攻防世界CTF平台-Reverse逆向类——56、tar-tar-binks(Mac平台下的64位动态链接共享库.dylib逆向)相关推荐

  1. XCTF-攻防世界CTF平台-Reverse逆向类——57、re5-packed-movement(linux32位ELF文件、movfuscator代码混淆)

    目录标题 方法一:搜索字节序列 方法二:IDC脚本 方法三:Python脚本: 方法四:bgrep工具 先查看文件信息:   是linux下的32位ELF文件,且被加了UPX的壳   下载最新版的UP ...

  2. XCTF-攻防世界CTF平台-Reverse逆向类——52、handcrafted-pyc(Python的pyc文件逆向)

    下载题目附件之后,查看附件52: 发现它就是一个Python代码文件 #!/usr/bin/env python # -*- coding: utf-8 -*-import marshal, zlib ...

  3. 【ics-05 | mfw】攻防世界CTF题WP

    攻防世界CTF题WP ics-05 所需知识 解题步骤 学习知识 php伪协议(文件包含漏洞中使用) preg_place函数 mfw 所需知识 解题步骤 学习知识 Dirserach工具 GitHa ...

  4. XCTF攻防世界 Normal_RSA

    XCTF攻防世界 Normal_RSA 实验环境: windows 10 实验所需工具: python工具: yafu (可以在https://github.com/DarkenCode/yafu上下 ...

  5. XCTF攻防世界Web新手入门题大全

    XCTF攻防世界Web之WriteUp无图版 (Tips:有图版本,请移步我的资源,自行下载doc文档) 0x00 准备 [内容] 在xctf官网注册账号,即可食用. [目录] 目录 0x01 vie ...

  6. XCTF攻防世界Web之WriteUp

    XCTF攻防世界Web之WriteUp 0x00 准备 [内容] 在xctf官网注册账号,即可食用. [目录] 目录 0x01 view-source2 0x02 get post3 0x03 rob ...

  7. XCTF攻防世界练习区-web题(新手)

    XCTF攻防世界练习区-web题(新手) https://adworld.xctf.org.cn/task?now_checked_num=3&name=web 001 view_source ...

  8. XCTF攻防世界BABYRE逆向

    攻防世界BABYRE逆向 拿到题目,查壳如下: 拖拽IDA Pro7.5打开,查看main函数,代码如下: 可以看到: (*(unsigned int (__fastcall **)(char *)) ...

  9. XCTF 攻防世界 web 高手进阶区

    文章目录 ics-07 shrine( flask + jinja2 的 SSTI) easytornado(模板注入) upload(文件名注入) supersqli(堆叠注入) php_rce(T ...

最新文章

  1. activeMQ 本地测试
  2. R语言Apriori算法关联规则挖掘:使用interestMeasure函数评估挖掘到的规则(包括覆盖率(coverage)和FishersExactTest)、置信度最高的五条规则(top five
  3. union all怎么用在循环里_欧式边框在PPT里怎么用?我怎么好像没见过
  4. 简单的节流函数throttle
  5. 【Python】解决浮点数间运算存在不确定尾数的问题
  6. 【Hisi系列】之软件平台开发(MPP相关)
  7. ui uview 安卓开发_HarmonyOS 2.0手机开发者Beta公测招募
  8. yield关键字 C#
  9. 基于模糊PID控制的光伏系统最大功率点跟踪的研究
  10. 汽车类自媒体怎么找素材?这几个办法很好用
  11. java自制语音识别,JAVA作的语音识别
  12. python获取软件内数据_三种 Python 网络内容抓取工具与爬虫
  13. Android第七讲笔记(圆形图片,网络图片,下拉刷新,上拉加载)
  14. 计算H时M分S秒以后是_关于工程量计算-深圳工程量计算培训
  15. 国瀚实业|个人如何投资理财
  16. Matlab——向量及其运算
  17. 使用Eclips开发java程序
  18. 第四节课 hadoop总结
  19. Java泛型方法的定义
  20. 关于九宫格的一个算法,求大神助攻

热门文章

  1. 前端图形验证码的实现
  2. 接口定义语言IDL,COM
  3. csr867x入门之gatt使用(五)
  4. 在使用Less除法运算时,报错(css不出结果)
  5. 全网招募P图高手!阿里巴巴持续训练鉴假AI
  6. 转 虫师的selenium借助AutoIt识别上传(下载)详解
  7. python学习笔记--虫师
  8. 「深圳买新房」有哪些靠谱的平台?
  9. 8.1SQL概述与数据库定义
  10. opencv人脸检测+美颜