RE
checkin
题目说推荐虚拟机做。
首先尝试xp,结果报错,报错信息中意外得知这是调用的ruby.exe。
然后试了下win7,可以正常运行。
如果输入flag的时候,不输入,直接回车,也会有下面的报错:
所以直接来到报错中出现的目录下,找到ruby脚本。
注意程序运行完之后会删除上面解压出来的那个目录,所以运行程序后,停在输入flag的那一步,接着去找上面的目录中的ruby脚本。
虚拟机没安装vmware,直接把ruby脚本截个图吧:
然后在线解aes就可以了。
队友用了一个叫processmonitor的工具,比我这碰巧遇到报错信息的方法要高明的多,欢迎去看一下他的题解。
EasyRe
一个vm。
动调来到vm指令的相关代码处,并分析各个操作码的含义:
int __cdecl sub_8048838(_DWORD *a1)
{
int v1; // ecx
_BYTE *v2; // ST28_4
int result; // eax
unsigned int v4; // et1
unsigned int v5; // [esp+2Ch] [ebp-Ch]
v5 = __readgsdword(0x14u);
while ( 1 )
{
if ( *(_BYTE *)a1[8] == 113 ) // 没用到
{
a1[6] -= 4;
*(_DWORD *)a1[6] = *(_DWORD *)(a1[8] + 1);
a1[8] += 5;
}
if ( *(_BYTE *)a1[8] == 65 ) // a1[1] += a1[2]
{
a1[1] += a1[2];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 66 ) // a1[1] -= a1[4]
{
a1[1] -= a1[4];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 67 ) // a1[1] *= a1[3]
{
a1[1] *= a1[3];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 68 ) // a1[1] /= a1[5]
{
a1[1] /= a1[5];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 128 ) // op ? (int)num a1[9] = num opn += 6
{
a1[return_a1_add_32_add_1((int)a1, 1u)] = *(_DWORD *)(a1[8] + 2);
a1[8] += 6;
}
if ( *(_BYTE *)a1[8] == 119 ) // a1[1] ^= a1[9]
{
a1[1] ^= a1[9];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 83 ) // 没用到
{
sub_80485F0(*(char *)a1[3]);
a1[8] += 2;
}
if ( *(_BYTE *)a1[8] == 34 ) // a1[1] >>= a1[2]
{
v1 = a1[2];
a1[1] >>= v1;
++a1[8];
}
if ( *(_BYTE *)a1[8] == 35 ) // a1[1] <<= a1[2]
{
v1 = a1[2];
a1[1] <<= v1;
++a1[8];
}
if ( *(_BYTE *)a1[8] == 153 ) // 跳出循环
break;
if ( *(_BYTE *)a1[8] == 118 ) // 没用到
{
a1[3] = *(_DWORD *)a1[6];
*(_DWORD *)a1[6] = 0;
a1[6] += 4;
a1[8] += 5;
}
if ( *(_BYTE *)a1[8] == 84 ) // 没用到
{
v2 = (_BYTE *)a1[3];
*v2 = sub_8048580();
a1[8] += 2;
}
if ( *(_BYTE *)a1[8] == 48 ) // a1[1] |= a1[2]
{
a1[1] |= a1[2];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 49 ) // a1[1] &= a1[2]
{
a1[1] &= a1[2];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 9 ) //a1[1] = 输入int64
{
a1[1] = dword_804B28C;
++a1[8];
}
if ( *(_BYTE *)a1[8] == 16 ) // a1[9] = a1[1]
{
a1[9] = a1[1];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 17 ) // printf("%p\n", a1[1])
{
printf((const char *)&unk_804920C, a1[1]);
++a1[8];
}
if ( *(_BYTE *)a1[8] == 160 ) // if (a1[1] == 0x26F8D100) opn++ else exit()
{
if ( a1[1] == 653840640 )
++a1[8];
else
exit();
}
if ( *(_BYTE *)a1[8] == 161 ) // 输入flag, flag = byte_804B2E0
{
printf("flag:");
sub_8048560(0, (int)byte_804B2E0, 40);
if ( strlen((int)byte_804B2E0) != 33 )
exit();
++a1[8];
}
if ( *(_BYTE *)a1[8] == 177 ) // a1[9] = dword_804B2A0[0]
{
a1[9] = dword_804B2A0[0];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 178 ) // a1[9] = dword_804B2A4
{
a1[9] = dword_804B2A4;
++a1[8];
}
if ( *(_BYTE *)a1[8] == 164 ) // op byte(num) ? ? dword_804B2A0[num] = a1[1] opn += 4(后两字节无效)
{
dword_804B2A0[*(unsigned __int8 *)(a1[8] + 1)] = a1[1];
a1[8] += 4;
}
if ( *(_BYTE *)a1[8] == 179 ) // a1[9] = dword_804B2A8
{
a1[9] = dword_804B2A8;
++a1[8];
}
if ( *(_BYTE *)a1[8] == 180 ) // a1[9] = dword_804B2AC
{
a1[9] = dword_804B2AC;
++a1[8];
}
if ( *(_BYTE *)a1[8] == 193 ) // op byte(num) a1[1] = byte_804B2E0[num] opn += 2
{
a1[1] = byte_804B2E0[*(unsigned __int8 *)(a1[8] + 1)];
a1[8] += 2;
}
if ( *(_BYTE *)a1[8] == 194 ) // op (int)num if (a1[1] == num) opn += 5
{
if ( a1[1] != *(_DWORD *)(a1[8] + 1) )
exit();
a1[8] += 5;
}
}
v4 = __readgsdword(0x14u);
result = v4 ^ v5;
if ( v4 != v5 )
result = sub_8048590(v1);
return result;
}
同样是动调拿到vm的代码,并dump出来,然后用下面的脚本分析vm:
dic = [
(65, 'a1[1] += a1[2]', 1),
(66, 'a1[1] -= a1[4]', 1),
(67, 'a1[1] *= a1[3]', 1),
(68, 'a1[1] /= a1[5]', 1),
(128, 'a1[?] = %d', 6),
(119, 'a1[1] ^= a1[9]', 1),
(34, 'a1[1] >>= a1[2]', 1),
(35, 'a1[1] <<= a1[2]', 1),
(153, '跳出循环', 1),
(48, 'a1[1] |= a1[2]', 1),
(49, 'a1[1] &= a1[2]', 1),
(9, 'a1[1] = 输入int', 1),
(16, 'a1[9] = a1[1]', 1),
(17, 'printf("%p\n", a1[1])', 1),
(160, 'if (a1[1] == 0x26F8D100) opn++ else exit()', 1),
(161, '输入flag, flag = byte_804B2E0', 1),
(177, 'a1[9] = dword_804B2A0[0]', 1),
(178, 'a1[9] = dword_804B2A4', 1),
(164, 'dword_804B2A0[%d] = a1[1]', 4),
(179, 'a1[9] = dword_804B2A8', 1),
(180, 'a1[9] = dword_804B2AC', 1),
(193, 'a1[1] = byte_804B2E0[%d]', 2),
(194, 'if (a1[1] == %d)', 5)
]
def get_int(b):
import struct
return struct.unpack('I', b)[0]
with open('dump', 'rb')as f:
b = f.read()
opn = 0
while (True):
op = b[opn]
for i in range(len(dic)):
if op == dic[i][0]:
code = dic[i][1]
if op == 128:
num = get_int(b[opn+2:opn+2+4])
print(code % num)
elif op == 164 or op == 193:
num = b[opn+1]
print(code % num)
elif op == 194:
num = get_int(b[opn+1:opn+1+4])
print(code % num)
else:
print(code)
opn += dic[i][2]
break
分析输出的结果:
a1[1] = 输入int
a1[9] = a1[1]
a1[2] = 13
a1[1] >>= a1[2]
a1[1] ^= a1[9] //a1[1] = a1[1] ^ (a1[1] >> 13)
a1[9] = a1[1] //a1[9] = a1[1]
a1[2] = 9
a1[1] <<= a1[2]
a1[2] = 2029229568
a1[1] &= a1[2]
a1[1] ^= a1[9] //a1[1] = ((a1[1] << 9) & 0x78f39600) ^ a1[1]
a1[9] = a1[1] //a1[9] = a1[1]
a1[2] = 17
a1[1] <<= a1[2]
a1[2] = 2245263360
a1[1] &= a1[2]
a1[1] ^= a1[9] //a1[1] = ((a1[1] << 17) & 0x85d40000) ^ a1[1]
a1[9] = a1[1] //a1[9] = a1[1]
a1[2] = 19
a1[1] >>= a1[2]
a1[1] ^= a1[9] //a1[1] = (a1[1] >> 19) ^ a1[1]
if (a1[1] == 0x26F8D100) opn++ else exit()
a1[1] = 输入int
a1[?] = 255
a1[1] &= a1[2]
a1[?] = 2
a1[1] *= a1[3]
a1[?] = 24
a1[1] += a1[2]
dword_804B2A0[0] = a1[1] // (a1[1] & 255) * 2 + 24
a1[1] = 输入int
a1[?] = 8
a1[1] >>= a1[2]
a1[?] = 255
a1[1] &= a1[2]
a1[?] = 7
a1[1] /= a1[5]
a1[?] = 33
a1[1] += a1[2]
dword_804B2A0[1] = a1[1] // ((a1[1] >> 8) & 255) / 7 + 33
a1[1] = 输入int
a1[?] = 16
a1[1] >>= a1[2]
a1[?] = 255
a1[1] &= a1[2]
a1[?] = 187
a1[1] ^= a1[9]
a1[?] = 255
a1[1] += a1[2]
dword_804B2A0[2] = a1[1] // (((a1[1] >> 16) & 255) ^ 187) + 255
a1[1] = 输入int
a1[?] = 24
a1[1] >>= a1[2]
a1[?] = 255
a1[1] &= a1[2]
a1[?] = 160
a1[1] -= a1[4]
a1[?] = 119
a1[1] += a1[2]
dword_804B2A0[3] = a1[1] // ((a1[1] >> 24) & 255) - 160 + 119
输入flag, flag = byte_804B2E0
a1[1] = byte_804B2E0[0]
a1[9] = dword_804B2A0[0]
a1[1] ^= a1[9]
if (a1[1] == 267) // if (flag[i] ^ dword_804B2A0[0] == 267)
a1[1] = byte_804B2E0[1]
a1[9] = dword_804B2A4
a1[1] ^= a1[9]
if (a1[1] == 122) // if (flag[i] ^ dword_804B2A0[1] == 122)
a1[1] = byte_804B2E0[2]
a1[9] = dword_804B2AC
a1[1] ^= a1[9]
if (a1[1] == 149) // if (flag[i] ^ dword_804B2A0[3] == 149)
a1[1] = byte_804B2E0[3]
a1[9] = dword_804B2A8
a1[1] ^= a1[9]
if (a1[1] == 262) // if (flag[i] ^ dword_804B2A0[2] == 262)
a1[1] = byte_804B2E0[4]
a1[9] = dword_804B2A4
a1[1] ^= a1[9]
if (a1[1] == 125) // if (flag[i] ^ dword_804B2A0[1] == 125)
a1[1] = byte_804B2E0[5]
a1[9] = dword_804B2AC
a1[1] ^= a1[9]
if (a1[1] == 173)
a1[1] = byte_804B2E0[6]
a1[9] = dword_804B2A0[0]
a1[1] ^= a1[9]
if (a1[1] == 303)
a1[1] = byte_804B2E0[7]
a1[9] = dword_804B2A8
a1[1] ^= a1[9]
if (a1[1] == 357)
a1[1] = byte_804B2E0[8]
a1[9] = dword_804B2A0[0]
a1[1] ^= a1[9]
if (a1[1] == 301)
a1[1] = byte_804B2E0[9]
a1[9] = dword_804B2A0[0]
a1[1] ^= a1[9]
if (a1[1] == 303)
a1[1] = byte_804B2E0[10]
a1[9] = dword_804B2A8
a1[1] ^= a1[9]
if (a1[1] == 313)
a1[1] = byte_804B2E0[11]
a1[9] = dword_804B2A8
a1[1] ^= a1[9]
if (a1[1] == 269)
a1[1] = byte_804B2E0[12]
a1[9] = dword_804B2AC
a1[1] ^= a1[9]
if (a1[1] == 187)
a1[1] = byte_804B2E0[13]
a1[9] = dword_804B2A4
a1[1] ^= a1[9]
if (a1[1] == 8)
a1[1] = byte_804B2E0[14]
a1[9] = dword_804B2A8
a1[1] ^= a1[9]
if (a1[1] == 269)
a1[1] = byte_804B2E0[15]
a1[9] = dword_804B2A0[0]
a1[1] ^= a1[9]
if (a1[1] == 319)
a1[1] = byte_804B2E0[16]
a1[9] = dword_804B2A8
a1[1] ^= a1[9]
if (a1[1] == 314)
a1[1] = byte_804B2E0[17]
a1[9] = dword_804B2A8
a1[1] ^= a1[9]
if (a1[1] == 353)
a1[1] = byte_804B2E0[18]
a1[9] = dword_804B2A4
a1[1] ^= a1[9]
if (a1[1] == 87)
a1[1] = byte_804B2E0[19]
a1[9] = dword_804B2A0[0]
a1[1] ^= a1[9]
if (a1[1] == 288)
a1[1] = byte_804B2E0[20]
a1[9] = dword_804B2A8
a1[1] ^= a1[9]
if (a1[1] == 269)
a1[1] = byte_804B2E0[21]
a1[9] = dword_804B2A0[0]
a1[1] ^= a1[9]
if (a1[1] == 319)
a1[1] = byte_804B2E0[22]
a1[9] = dword_804B2A8
a1[1] ^= a1[9]
if (a1[1] == 319)
a1[1] = byte_804B2E0[23]
a1[9] = dword_804B2AC
a1[1] ^= a1[9]
if (a1[1] == 181)
a1[1] = byte_804B2E0[24]
a1[9] = dword_804B2A0[0]
a1[1] ^= a1[9]
if (a1[1] == 275)
a1[1] = byte_804B2E0[25]
a1[9] = dword_804B2AC
a1[1] ^= a1[9]
if (a1[1] == 160)
a1[1] = byte_804B2E0[26]
a1[9] = dword_804B2A0[0]
a1[1] ^= a1[9]
if (a1[1] == 289)
a1[1] = byte_804B2E0[27]
a1[9] = dword_804B2A8
a1[1] ^= a1[9]
if (a1[1] == 269)
a1[1] = byte_804B2E0[28]
a1[9] = dword_804B2A4
a1[1] ^= a1[9]
if (a1[1] == 11)
a1[1] = byte_804B2E0[29]
a1[9] = dword_804B2A8
a1[1] ^= a1[9]
if (a1[1] == 313)
a1[1] = byte_804B2E0[30]
a1[9] = dword_804B2A0[0]
a1[1] ^= a1[9]
if (a1[1] == 371)
a1[1] = byte_804B2E0[31]
a1[9] = dword_804B2A4
a1[1] ^= a1[9]
if (a1[1] == 70)
跳出循环
可以看出首先是输入一个数,依次经过下面的运算后判断是否和 0x26F8D100相等。
a1[1] = a1[1] ^ (a1[1] >> 13)
a1[1] = ((a1[1] << 9) & 0x78f39600) ^ a1[1]
a1[1] = ((a1[1] << 17) & 0x85d40000) ^ a1[1]
a1[1] = (a1[1] >> 19) ^ a1[1]
很巧的是,前几天的七夕,我闲得没事干,随手写了个加解密的小程序,关键逻辑简直和本题的一模一样,我是万万没想到啊。
文章发在了看雪上,一个有趣的加密小算法及其逆向,里面有分析这个类型的算式如何逆向,同时做了一定的推广,也提供了加解密的c语言代码(本题甚至可以直接把我那篇文章提供的c代码修改一下即可)。建议大家先去看一下。
有一点不同的是,本题多了个 & 0x78f39600
。其实不过是稍微进一步的拓展而已,看完上面的那篇博文,你应该能够想明白这个应该怎么处理。如果不明白,那么将下面的脚本和上面提到的我的那篇博文中的脚本对比下差异,就应该会懂了。
下面的脚本修改自上面提到的我的那篇博文,可以求出这个输入的数来:
#include <stdio.h>
#include <math.h>
unsigned int getAnsOfPowerOfTwo(int a, int b){
//求2的幂的和
unsigned int ans = 0;
int i;
for (i = a; i < b; i++){
ans += pow(2, i);
}
return ans;
}
unsigned int getBit(const unsigned int n, int i){
//取某一位的bit
unsigned int t = pow(2, i);
return (t & n) >> i;
}
unsigned int rightShiftXor(const unsigned int n, int m){
unsigned int r = n & getAnsOfPowerOfTwo(0, 32 - m);
unsigned int l = n & getAnsOfPowerOfTwo(32 - m, 32);
unsigned int t = l;
int i, t_i;
for (i = 31 - m; i >= 0; i--){
t_i = getBit(t, i + m) ^ getBit(n, i);
t += t_i << i;
}
return t;
}
unsigned int leftShiftAndXor(const unsigned int n, int m, unsigned int x){
unsigned int r = n & getAnsOfPowerOfTwo(0, m);
unsigned int l = n & getAnsOfPowerOfTwo(m, 32);
unsigned int t = r;
int i, t_i;
for (i = m; i < 32; i++){
if (getBit(x, i) == 1){
t_i = getBit(t, i - m) ^ getBit(n, i);
t += t_i << i;
}
else{
t_i = getBit(n, i);
t += t_i << i;
}
}
return t;
}
unsigned int decrypt(c){
unsigned int o = rightShiftXor(c, 19);
unsigned int p = leftShiftAndXor(o, 17, 0x85d40000);
unsigned int q = leftShiftAndXor(p, 9, 0x78f39600);
unsigned int r = rightShiftXor(q, 13);
return r;
}
int main(){
unsigned int c = 0x26F8D100;
unsigned int p = decrypt(c);
printf("\ndecrypt(0x%x) = 0x%x\n", c, p);
return 0;
}
当然,这个输入只是个int而已,我觉得可以用angr搞,不过我没试过,不太清楚具体行不行。
后面的逻辑就很简单了,直接写脚本:
a = 4293442714
a = 0xffe8bc9a
l = [0] * 4
l[0] = (a & 255) * 2 + 24
l[1] = ((a >> 8) & 255) // 7 + 33
l[2] = (((a >> 16) & 255) ^ 187) + 255
l[3] = ((a >> 24) & 255) - 160 + 119
print(l)
flag = [0] * 32
flag[0] = l[0] ^ 267
flag[1] = l[1] ^ 122
flag[2] = l[3] ^ 149
flag[3] = l[2] ^ 262
flag[4] = l[1] ^ 125
flag[5] = l[3] ^ 173
flag[6] = l[0] ^ 303
flag[7] = l[2] ^ 357
flag[8] = l[0] ^ 301
flag[9] = l[0] ^ 303
flag[10] = l[2] ^ 313
flag[11] = l[2] ^ 269
flag[12] = l[3] ^ 187
flag[13] = l[1] ^ 8
flag[14] = l[2] ^ 269
flag[15] = l[0] ^ 319
flag[16] = l[2] ^ 314
flag[17] = l[2] ^ 353
flag[18] = l[1] ^ 87
flag[19] = l[0] ^ 288
flag[20] = l[2] ^ 269
flag[21] = l[0] ^ 319
flag[22] = l[2] ^ 319
flag[23] = l[3] ^ 181
flag[24] = l[0] ^ 275
flag[25] = l[3] ^ 160
flag[26] = l[0] ^ 289
flag[27] = l[2] ^ 269
flag[28] = l[1] ^ 11
flag[29] = l[2] ^ 313
flag[30] = l[0] ^ 371
flag[31] = l[1] ^ 70
print(flag)
print(''.join(map(chr, flag)))
WannaFlag
本题文本框内开玩笑说6666RMB联系出题人买密钥,我闲得慌,还真去加了haivk大佬的QQ,哈哈。
界面看着很炫酷,其实不看花里胡哨的东西的话,逻辑炒鸡简单,签到题难度。
别跑偏了,不需要你看懂那个解密函数。只需要看sub_402280的关键代码:
上图黄框中的代码也不需要看,不要想复杂了。密钥长度不会超过64的,直接看后面的一小段即可。
加解密需要用到v38,v38与v37有关,而v37的值我们不清楚到底是啥意思,但好在v37的取值是0~6,所以爆破即可。
后面一小段的逻辑就是签到题难度,应该不需要我多说什么吧。
def __ROL1__(value, k):
k %= 8
return (((value << k)&0xff) | ((value >> (8-k))&0xff))&0xff
def __ROR1__(value, k):
k %= 8
return (((value >> k)&0xff) | ((value << (8-k))&0xff))&0xff
#with open(r'd:\dump', 'rb')as f:
# b = f.read()
b = b'N\xaea\xba\xe4+U\xaaY\xfcM\x02\x17k\x13\xa1A\xfe5\x0b\xb4\x0bR/F\xcc5\x82\xe5\x88P\x00'
byte_420AE0 = b"ANNAWGALFYBKVIAHMXTFCAACLAAAAYK\x00"
v58 = [0] * 32
for i in range(32):
v58[i] = __ROR1__(b[i], i) ^ byte_420AE0[i]
v58_2 = [0] * 32
for i in range(0, 7):
v38 = 1
if (i > 2):
for j in range(2, i):
v38 *= j
print(v38)
for k in range(32):
v58_2[k] = v38 ^ v58[k]
print(v58_2)
a = [119, 97, 110, 110, 97, 102, 108, 97, 103, 95, 105, 115, 95, 106, 117, 115, 116, 95, 97, 95, 112, 97, 112, 101, 114, 95, 116, 105, 103, 101, 114, 120]
print(''.join(map(chr, a)))
当然赛后完全可以再翻出解密函数来学习一波。
读入flag.bin:
创建一个CS模块中的密钥容器:
创建一个hash对象,0x8004表示采用的散列算法是SHA。等下生成key时,要用到这个hash对象:
计算密钥散列:
生成密钥,0x6801表示加密算法为RC4:
解密数据,写入文件:
归纳一下就是:
- CryptAcquireContextW生成CSP句柄
- CryptCreateHash创建hash对象,第二个参数指定散列算法
- CryptHashData计算密钥的散列,第一个参数是上一步生成的hash对象
- CryptDeriveKey生成密钥,第二个参数指定加密算法(是的,加密算法是在这一步指定的),第三个参数就是前面生成的散列对象。与之类似的还有个CryptGenKey,不过这个是随机生成密钥而非指定。
- CryptDecrypt解密
- 除此之外还有CryptReleaseContext释放CSP句柄,CryptDestroyKey释放密钥句柄,CryptDestroyHash释放hash对象。
Simulator
给了一个很小的obj文件,里面发现有lc3的字眼。
搜了下,lc3是一套精简指令集,风格类似arm。
官网有windows下的调试器。(愚蠢的我一开始居然打算在ubuntu里编译这个工具)
大概是这样的:
一个控制台,一个调试器。
ctrl+L导入题目的obj文件:
我不擅长动调,顺便打算利用这次机会,学习一下arm风格的汇编。
所以直接将结果导出,静态分析:
开始分析之前,我觉得有必要放几个题目中出现的指令:
然后是比较重要的跳转指令BR系列:
很重要的一个知识点:
The assembly language opcode BR is interpreted the same as BRnzp; that is, always branch to the target address.
也就是说本题中常见的BRnzp,和BR指令是一样的,相当于x86的jmp。
然后慢慢分析吧(建议把下面的分析复制到本地再看),我觉得已经炒鸡详细了,几乎每一步都注释了。当然量太大了,错误在所难免,不过应该不会影响理解。
Registers:
R0 x0000 0
R1 x0000 0
R2 x0000 0
R3 x0000 0
R4 x0000 0
R5 x0000 0
R6 x0000 0
R7 x0000 0
PC x3000 12288
IR x0000 0
CC Z
Memory:
x3000 1110000001111010 xE07A LEA R0, x307B ;WELCOME TO WORLD OF LC3
x3001 1111000000100010 xF022 TRAP PUTS
x3002 0010000001110111 x2077 LD R0, x307A ;0x0A,换行
x3003 1111000000100001 xF021 TRAP OUT
x3004 1110000010010010 xE092 LEA R0, x3097 ;PLEASE INPUT YOUR FLAG:
x3005 1111000000100010 xF022 TRAP PUTS
x3006 0010011011011110 x26DE LD R3, x30E5 ;R3 = [0x30E5] = 0x18 ;flag长度
x3007 1111000000100000 xF020 TRAP GETC ;从缓冲区接收一个字符
x3008 1111000000100001 xF021 TRAP OUT ;输出这个字符
x3009 0010001011011010 x22DA LD R1, x30E4 ;R1 = [0x30E4] = 0x4000
x300A 0001001001000011 x1243 ADD R1, R1, R3 ;R1 = R1 + R3
x300B 0111000001000000 x7040 STR R0, R1, #0 ;[R1 + 0] = R0 ;[0x4000] = R0,字符串存储在0x4000
x300C 0001011011111111 x16FF ADD R3, R3, #-1 ;R3 = R3 - 1 ;所以输入后的字符串的存储是倒序的
x300D 0000100000000001 x0801 BRN x300F
x300E 0000111111111000 x0FF8 BRNZP x3007
x300F 1110100011101111 xE8EF LEA R4, x30FF ;R4 = 0x30FF
x3010 0101010010100000 x54A0 AND R2, R2, #0 ;R2 = 0
x3011 0001001010000100 x1284 ADD R1, R2, R4 ;R1 = 0x30FF + R2
x3012 0110001001000000 x6240 LDR R1, R1, #0 ;R1 = [R1] = [0x30FF + R2]
x3013 0101000000100000 x5020 AND R0, R0, #0 ;R0 = 0
x3014 0010000001100010 x2062 LD R0, x3077 ;R0 = [0x3077]
x3015 1001000000111111 x903F NOT R0, R0 ;R0 = ~R0 = ~[0X3077]
x3016 0001000000100001 x1021 ADD R0, R0, #1 ;R0 = ~[0X3077] + 1
x3017 0001000001000000 x1040 ADD R0, R1, R0 ;R0 = [0x30FF + R2] + (~[0x3077] + 1) = [0x30FF + R2] - [0x3077]
x3018 0000010000001010 x040A BRZ x3023 ;意思是若R0等于0([0x30FF + R2] == [0x3077] = 0x11),则一直跳转到0x3023
x3019 0010000001011110 x205E LD R0, x3078
x301A 1001000000111111 x903F NOT R0, R0
x301B 0001000000100001 x1021 ADD R0, R0, #1
x301C 0001000001000000 x1040 ADD R0, R1, R0
x301D 0000010000010111 x0417 BRZ x3035 ;[0x30FF + R2] == [0x3078] = 0x13
x301E 0010000001011010 x205A LD R0, x3079
x301F 1001000000111111 x903F NOT R0, R0
x3020 0001000000100001 x1021 ADD R0, R0, #1
x3021 0001000001000000 x1040 ADD R0, R1, R0
x3022 0000010000100101 x0425 BRZ x3048 ;[0x30FF + R2] == [0x3079] = 0x14
x3023 0001001010100001 x12A1 ADD R1, R2, #1 ;R1 = R2 + 1
x3024 0001001100000001 x1301 ADD R1, R4, R1 ;R1 = R4 + R2 + 1 ;R4 = 0x30FF
x3025 0110001001000000 x6240 LDR R1, R1, #0 ;R1 = [R4 + R2 + 1]
x3026 0001110001100000 x1C60 ADD R6, R1, #0 ;R6 = R1
x3027 0001001010100010 x12A2 ADD R1, R2, #2 ;R1 = R2 + 2
x3028 0001001100000001 x1301 ADD R1, R4, R1 ;R1 = R4 + (R2 + 2)
x3029 0110001001000000 x6240 LDR R1, R1, #0 ;R1 = [R4 + R2 + 2]
x302A 0010000010111001 x20B9 LD R0, x30E4 ;R0 = [0x30E4] ;flag基址0x4000
x302B 0001000001100000 x1060 ADD R0, R1, #0 ;R0 = [0x30E4] + [R4 + R2 + 2]
x302C 0110000000000000 x6000 LDR R0, R0, #0 ;R0 = [[0x30E4] + [R4 + R2 + 2]] = flag[[0x30FF + R2 + 2]]
x302D 0001111000100000 x1E20 ADD R7, R0, #0 ;R7 = flag[[0x30FF + R2 + 2]]
x302E 0001101001100000 x1A60 ADD R5, R1, #0 ;R5 = [0x30FF + R2 + 2]
x302F 0000111000101001 x0E29 BRNZP x3059
x3030 0010001010110011 x22B3 LD R1, x30E4 ;R1 = [0x30E4] = 0x4000
x3031 0001001101000001 x1341 ADD R1, R5, R1 ;R1 = 0x4000 + [0x30FF + R2 + 2]
x3032 0111000001000000 x7040 STR R0, R1, #0 ;[R1] = R0 ;flag[[0x30FF + R2 + 2]] = [0x30FF + R2 + 1] + flag[[0x30FF + R2 + 2]]
x3033 0001010010100011 x14A3 ADD R2, R2, #3 ;R2 += 3
x3034 0000111111011100 x0FDC BRNZP x3011
x3035 0001001010100001 x12A1 ADD R1, R2, #1 ;R1 = R2 + 1
x3036 0001001100000001 x1301 ADD R1, R4, R1 ;R1 = R4 + R2 + 1
x3037 0110001001000000 x6240 LDR R1, R1, #0 ;R1 = [R4 + R2 + 1]
x3038 0010000010101011 x20AB LD R0, x30E4 ;R0 = 0x4000
x3039 0001000000000001 x1001 ADD R0, R0, R1 ;R0 = 0X4000 + [R4 + R2 + 1]
x303A 0110110000000000 x6C00 LDR R6, R0, #0 ;R6 = [R0] = FLAG[[0x30FF + R2 + 1]]
x303B 0001001010100010 x12A2 ADD R1, R2, #2 ;R1 = R2 + 2
x303C 0001001100000001 x1301 ADD R1, R4, R1 ;R1 = R4 + R1 = R4 + R2 + 2
x303D 0110001001000000 x6240 LDR R1, R1, #0 ;R1 = [0x30FF + R2 + 2]
x303E 0010000010100101 x20A5 LD R0, x30E4 ;R0 = 0X4000
x303F 0001000000000001 x1001 ADD R0, R0, R1 ;R0 = 0X4000 + [0x30FF + R2 + 2]
x3040 0001101001100000 x1A60 ADD R5, R1, #0 ;R5 = [0x30FF + R2 + 2]
x3041 0110111000000000 x6E00 LDR R7, R0, #0 ;R7 = [0X4000 + [0x30FF + R2 + 2]] = FLAG[[0x30FF + R2 + 2]]
x3042 0000111000011000 x0E18 BRNZP x305B
x3043 0010001010100000 x22A0 LD R1, x30E4 ;R1 = 0X4000
x3044 0001001001000101 x1245 ADD R1, R1, R5 ;R1 = 0X4000 + [0x30FF + R2 + 2]
x3045 0111000001000000 x7040 STR R0, R1, #0 ;[R1] = R0 ;FLAG[[0x30FF + R2 + 2]] = ((FLAG[[0x30FF + R2 + 1]]) & (~(FLAG[[0x30FF + R2 + 2]]))) + ((~FLAG[[0x30FF + R2 + 1]]) & (FLAG[[0x30FF + R2 + 2]]))
x3046 0001010010100011 x14A3 ADD R2, R2, #3 ;R2 = R2 + 3
x3047 0000111111001001 x0FC9 BRNZP x3011
x3048 0001001010100001 x12A1 ADD R1, R2, #1 ;R1 = R2 + 1
x3049 0001001100000001 x1301 ADD R1, R4, R1 ;R1 = R4 + R2 + 1
x304A 0110001001000000 x6240 LDR R1, R1, #0 ;R1 = [R4 + R2 + 1]
x304B 0001110001100000 x1C60 ADD R6, R1, #0 ;R6 = R1 = [R4 + R2 + 1]
x304C 0001001010100010 x12A2 ADD R1, R2, #2 ;R1 = R2 + 2
x304D 0001001100000001 x1301 ADD R1, R4, R1 ;R1 = R4 + R2 + 2
x304E 0110001001000000 x6240 LDR R1, R1, #0 ;R1 = [R4 + R2 + 2]
x304F 0010101010010101 x2A95 LD R5, x30E5 ;R5 = 0x18
x3050 1001001001111111 x927F NOT R1, R1 ;R1 = ~R1 ;R1 = ~[R4 + R2 + 2]
x3051 0001001001100001 x1261 ADD R1, R1, #1 ;R1 = ~[R4 + R2 + 2] + 1
x3052 0001101101000001 x1B41 ADD R5, R5, R1 ;R5 = 0x18 + (~[R4 + R2 + 2] + 1) ;取非再加一的数学含义是取相反数,R5是用来标志循环是否结束的变量,初值0x18,终值为0.
x3053 0001111101100000 x1F60 ADD R7, R5, #0 ;R7 = R5 = 0x18 + (~[0x30FF + R2 + 2] + 1) ;考虑到[0x30FF + R2 + 2]的值为0x0~0x18,所以结果是0x18 - i,同时别忘了前面说过的字符串是倒序存储的
x3054 0000111000001100 x0E0C BRNZP x3061
x3055 0001101101100000 x1B60 ADD R5, R5, #0 ;if (R5 == 0) ????可能会影响标志位????
x3056 0000010000010101 x0415 BRZ x306C ;GOTO SUCCESS
x3057 0001010010100011 x14A3 ADD R2, R2, #3 ;R2 += 3
x3058 0000111110111000 x0FB8 BRNZP x3011
x3059 0001000110000111 x1187 ADD R0, R6, R7 ;R0 = [0x30FF + R2 + 1] + flag[[0x30FF + R2 + 2]]
x305A 0000111111010101 x0FD5 BRNZP x3030
x305B 1001000110111111 x91BF NOT R0, R6 ;R0 = ~R6 = ~FLAG[[0x30FF + R2 + 1]]
x305C 0101000000000111 x5007 AND R0, R0, R7 ;R0 = (~FLAG[[0x30FF + R2 + 1]]) & (FLAG[[0x30FF + R2 + 2]])
x305D 1001001111111111 x93FF NOT R1, R7 ;R1 = ~(FLAG[[0x30FF + R2 + 2]])
x305E 0101001110000001 x5381 AND R1, R6, R1 ;R1 = (FLAG[[0x30FF + R2 + 1]]) & (~(FLAG[[0x30FF + R2 + 2]]))
x305F 0001000001000000 x1040 ADD R0, R1, R0 ;R0 = ((FLAG[[0x30FF + R2 + 1]]) & (~(FLAG[[0x30FF + R2 + 2]]))) + ((~FLAG[[0x30FF + R2 + 1]]) & (FLAG[[0x30FF + R2 + 2]]))
x3060 0000111111100010 x0FE2 BRNZP x3043
x3061 0010000010000010 x2082 LD R0, x30E4 ;R0 = 0X4000
x3062 0001000000000110 x1006 ADD R0, R0, R6 ;R0 = 0X4000 + [0x30FF + R2 + 1]
x3063 0110000000000000 x6000 LDR R0, R0, #0 ;R0 = [0X4000 + [0x30FF + R2 + 1]] = FLAG[[0x30FF + R2 + 1]]
x3064 1110001010000001 xE281 LEA R1, x30E6 ;R1 = 0x30E6 ;这里是LEA,不是LDR,我个老花眼看错了,怪不得下一条指令不太对劲。
x3065 0001001001000111 x1247 ADD R1, R1, R7 ;R1 = 0x30E6 + 0x18 + (~[0x30FF + R2 + 2] + 1)
x3066 0110001001000000 x6240 LDR R1, R1, #0 ;R1 = [0x30E6 + 0x18 + (~[0x30FF + R2 + 2] + 1)]
x3067 1001001001111111 x927F NOT R1, R1 ;R1 = ~[0x30E6 + 0x18 + (~[0x30FF + R2 + 2] + 1)]
x3068 0001001001100001 x1261 ADD R1, R1, #1 ;R1 = ~[0x30E6 + 0x18 + (~[0x30FF + R2 + 2] + 1)] + 1 ;取[0x30E6 + 0x18 + (~[0x30FF + R2 + 2] + 1)]的相反数
x3069 0001000000000001 x1001 ADD R0, R0, R1 ;R0 = FLAG[[0x30FF + R2 + 1]] + (~[0x30E6 + 0x18 + (~[0x30FF + R2 + 2] + 1)] + 1) = FLAG[[0x30FF + R2 + 1]] - [0x30E6 + 0x18 + (~[0x30FF + R2 + 2] + 1)],flag密文比较
x306A 0000010111101010 x05EA BRZ x3055 ;二者相等则继续
x306B 0000111000000101 x0E05 BRNZP x3071 ;不相等说明flag不对,GOTO try again
x306C 0010000000001101 x200D LD R0, x307A ;换行
x306D 1111000000100001 xF021 TRAP OUT
x306E 1110000001000000 xE040 LEA R0, x30AF ;SUCCESS!
x306F 1111000000100010 xF022 TRAP PUTS
x3070 0000111000000101 x0E05 BRNZP x3076
x3071 0010000000001000 x2008 LD R0, x307A ;换行
x3072 1111000000100001 xF021 TRAP OUT
x3073 1110000001100101 xE065 LEA R0, x30D9 ;TRY AGAIN!
x3074 1111000000100010 xF022 TRAP PUTS
x3075 0000111000000000 x0E00 BRNZP x3076
x3076 1111000000100101 xF025 TRAP HALT
x3077 0000000000010001 x0011 NOP
x3078 0000000000010011 x0013 NOP
x3079 0000000000010100 x0014 NOP
x307A 0000000000001010 x000A NOP
x307B 0000000001010111 x0057 NOP ;W
x307C 0000000001100101 x0065 NOP ;e
x307D 0000000001101100 x006C NOP ;l
x307E 0000000001100011 x0063 NOP ;c
x307F 0000000001101111 x006F NOP ;o
x3080 0000000001101101 x006D NOP ;m
x3081 0000000001100101 x0065 NOP ;e
x3082 0000000000100000 x0020 NOP
x3083 0000000001110100 x0074 NOP
x3084 0000000001101111 x006F NOP
x3085 0000000000100000 x0020 NOP
x3086 0000000001110100 x0074 NOP
x3087 0000000001101000 x0068 NOP
x3088 0000000001100101 x0065 NOP
x3089 0000000000100000 x0020 NOP
x308A 0000000001110111 x0077 NOP
x308B 0000000001101111 x006F NOP
x308C 0000000001110010 x0072 NOP
x308D 0000000001101100 x006C NOP
x308E 0000000001100100 x0064 NOP
x308F 0000000000100000 x0020 NOP
x3090 0000000001101111 x006F NOP
x3091 0000000001100110 x0066 NOP
x3092 0000000000100000 x0020 NOP
x3093 0000000001001100 x004C NOP
x3094 0000000001000011 x0043 NOP
x3095 0000000000110011 x0033 NOP
x3096 0000000000000000 x0000 NOP
x3097 0000000001010000 x0050 NOP
x3098 0000000001101100 x006C NOP
x3099 0000000001100101 x0065 NOP
x309A 0000000001100001 x0061 NOP
x309B 0000000001110011 x0073 NOP
x309C 0000000001100101 x0065 NOP
x309D 0000000000100000 x0020 NOP
x309E 0000000001101001 x0069 NOP
x309F 0000000001101110 x006E NOP
x30A0 0000000001110101 x0075 NOP
x30A1 0000000001110000 x0070 NOP
x30A2 0000000001110100 x0074 NOP
x30A3 0000000000100000 x0020 NOP
x30A4 0000000001111001 x0079 NOP
x30A5 0000000001101111 x006F NOP
x30A6 0000000001110101 x0075 NOP
x30A7 0000000001110010 x0072 NOP
x30A8 0000000000100000 x0020 NOP
x30A9 0000000001100110 x0066 NOP
x30AA 0000000001101100 x006C NOP
x30AB 0000000001100001 x0061 NOP
x30AC 0000000001100111 x0067 NOP
x30AD 0000000000111010 x003A NOP
x30AE 0000000000000000 x0000 NOP
x30AF 0000000001010011 x0053 NOP
x30B0 0000000001110101 x0075 NOP
x30B1 0000000001100011 x0063 NOP
x30B2 0000000001100011 x0063 NOP
x30B3 0000000001100101 x0065 NOP
x30B4 0000000001110011 x0073 NOP
x30B5 0000000001110011 x0073 NOP
x30B6 0000000000100001 x0021 NOP
x30B7 0000000000100000 x0020 NOP
x30B8 0000000001011001 x0059 NOP
x30B9 0000000001101111 x006F NOP
x30BA 0000000001110101 x0075 NOP
x30BB 0000000001110010 x0072 NOP
x30BC 0000000000100000 x0020 NOP
x30BD 0000000001100110 x0066 NOP
x30BE 0000000001101100 x006C NOP
x30BF 0000000001100001 x0061 NOP
x30C0 0000000001100111 x0067 NOP
x30C1 0000000000100000 x0020 NOP
x30C2 0000000001101001 x0069 NOP
x30C3 0000000001110011 x0073 NOP
x30C4 0000000000100000 x0020 NOP
x30C5 0000000001111000 x0078 NOP
x30C6 0000000001101101 x006D NOP
x30C7 0000000001100011 x0063 NOP
x30C8 0000000001110100 x0074 NOP
x30C9 0000000001100110 x0066 NOP
x30CA 0000000001111011 x007B NOP
x30CB 0000000001111011 x007B NOP
x30CC 0000000001111001 x0079 NOP
x30CD 0000000001101111 x006F NOP
x30CE 0000000001110101 x0075 NOP
x30CF 0000000001110010 x0072 NOP
x30D0 0000000000100000 x0020 NOP
x30D1 0000000001101001 x0069 NOP
x30D2 0000000001101110 x006E NOP
x30D3 0000000001110000 x0070 NOP
x30D4 0000000001110101 x0075 NOP
x30D5 0000000001110100 x0074 NOP
x30D6 0000000001111101 x007D NOP
x30D7 0000000001111101 x007D NOP
x30D8 0000000000000000 x0000 NOP
x30D9 0000000001010100 x0054 NOP
x30DA 0000000001110010 x0072 NOP
x30DB 0000000001111001 x0079 NOP
x30DC 0000000000100000 x0020 NOP
x30DD 0000000001100001 x0061 NOP ;a
x30DE 0000000001100111 x0067 NOP ;g
x30DF 0000000001100001 x0061 NOP ;a
x30E0 0000000001101001 x0069 NOP ;i
x30E1 0000000001101110 x006E NOP ;n
x30E2 0000000000100001 x0021 NOP ;!
x30E3 0000000000000000 x0000 NOP
x30E4 0100000000000000 x4000 JSRR R0
x30E5 0000000000011000 x0018 NOP
x30E6 0000000001101100 x006C NOP
x30E7 0000000000001111 x000F NOP
x30E8 0000000001010000 x0050 NOP
x30E9 0000000001101100 x006C NOP
x30EA 0000000001101110 x006E NOP
x30EB 0000000001000010 x0042 NOP
x30EC 0000000000101100 x002C NOP
x30ED 0000000000101100 x002C NOP
x30EE 0000000000011110 x001E NOP
x30EF 0000000000001100 x000C NOP
x30F0 0000000000001101 x000D NOP
x30F1 0000000000000000 x0000 NOP
x30F2 0000000000110011 x0033 NOP
x30F3 0000000000111101 x003D NOP
x30F4 0000000000010111 x0017 NOP
x30F5 0000000000000001 x0001 NOP
x30F6 0000000000101011 x002B NOP
x30F7 0000000000111100 x003C NOP
x30F8 0000000000001100 x000C NOP
x30F9 0000000000000010 x0002 NOP
x30FA 0000000000011101 x001D NOP
x30FB 0000000000011100 x001C NOP
x30FC 0000000000001001 x0009 NOP
x30FD 0000000000010001 x0011 NOP
x30FE 0000000000010001 x0011 NOP
x30FF 0000000000010011 x0013 NOP
x3100 0000000000000001 x0001 NOP
x3101 0000000000000000 x0000 NOP
x3102 0000000000010100 x0014 NOP
x3103 0000000000000000 x0000 NOP
x3104 0000000000000000 x0000 NOP
x3105 0000000000010011 x0013 NOP
x3106 0000000000000010 x0002 NOP
x3107 0000000000000001 x0001 NOP
x3108 0000000000010100 x0014 NOP
x3109 0000000000000001 x0001 NOP
x310A 0000000000000001 x0001 NOP
x310B 0000000000010011 x0013 NOP
x310C 0000000000000011 x0003 NOP
x310D 0000000000000010 x0002 NOP
x310E 0000000000010100 x0014 NOP
x310F 0000000000000010 x0002 NOP
x3110 0000000000000010 x0002 NOP
x3111 0000000000010011 x0013 NOP
x3112 0000000000000100 x0004 NOP
x3113 0000000000000011 x0003 NOP
x3114 0000000000010100 x0014 NOP
x3115 0000000000000011 x0003 NOP
x3116 0000000000000011 x0003 NOP
x3117 0000000000010011 x0013 NOP
x3118 0000000000000101 x0005 NOP
x3119 0000000000000100 x0004 NOP
x311A 0000000000010100 x0014 NOP
x311B 0000000000000100 x0004 NOP
x311C 0000000000000100 x0004 NOP
x311D 0000000000010011 x0013 NOP
x311E 0000000000000110 x0006 NOP
x311F 0000000000000101 x0005 NOP
x3120 0000000000010100 x0014 NOP
x3121 0000000000000101 x0005 NOP
x3122 0000000000000101 x0005 NOP
x3123 0000000000010011 x0013 NOP
x3124 0000000000000111 x0007 NOP
x3125 0000000000000110 x0006 NOP
x3126 0000000000010100 x0014 NOP
x3127 0000000000000110 x0006 NOP
x3128 0000000000000110 x0006 NOP
x3129 0000000000010011 x0013 NOP
x312A 0000000000001000 x0008 NOP
x312B 0000000000000111 x0007 NOP
x312C 0000000000010100 x0014 NOP
x312D 0000000000000111 x0007 NOP
x312E 0000000000000111 x0007 NOP
x312F 0000000000010011 x0013 NOP
x3130 0000000000001001 x0009 NOP
x3131 0000000000001000 x0008 NOP
x3132 0000000000010100 x0014 NOP
x3133 0000000000001000 x0008 NOP
x3134 0000000000001000 x0008 NOP
x3135 0000000000010011 x0013 NOP
x3136 0000000000001010 x000A NOP
x3137 0000000000001001 x0009 NOP
x3138 0000000000010100 x0014 NOP
x3139 0000000000001001 x0009 NOP
x313A 0000000000001001 x0009 NOP
x313B 0000000000010011 x0013 NOP
x313C 0000000000001011 x000B NOP
x313D 0000000000001010 x000A NOP
x313E 0000000000010100 x0014 NOP
x313F 0000000000001010 x000A NOP
x3140 0000000000001010 x000A NOP
x3141 0000000000010011 x0013 NOP
x3142 0000000000001100 x000C NOP
x3143 0000000000001011 x000B NOP
x3144 0000000000010100 x0014 NOP
x3145 0000000000001011 x000B NOP
x3146 0000000000001011 x000B NOP
x3147 0000000000010011 x0013 NOP
x3148 0000000000001101 x000D NOP
x3149 0000000000001100 x000C NOP
x314A 0000000000010100 x0014 NOP
x314B 0000000000001100 x000C NOP
x314C 0000000000001100 x000C NOP
x314D 0000000000010011 x0013 NOP
x314E 0000000000001110 x000E NOP
x314F 0000000000001101 x000D NOP
x3150 0000000000010100 x0014 NOP
x3151 0000000000001101 x000D NOP
x3152 0000000000001101 x000D NOP
x3153 0000000000010011 x0013 NOP
x3154 0000000000001111 x000F NOP
x3155 0000000000001110 x000E NOP
x3156 0000000000010100 x0014 NOP
x3157 0000000000001110 x000E NOP
x3158 0000000000001110 x000E NOP
x3159 0000000000010011 x0013 NOP
x315A 0000000000010000 x0010 NOP
x315B 0000000000001111 x000F NOP
x315C 0000000000010100 x0014 NOP
x315D 0000000000001111 x000F NOP
x315E 0000000000001111 x000F NOP
x315F 0000000000010011 x0013 NOP
x3160 0000000000010001 x0011 NOP
x3161 0000000000010000 x0010 NOP
x3162 0000000000010100 x0014 NOP
x3163 0000000000010000 x0010 NOP
x3164 0000000000010000 x0010 NOP
x3165 0000000000010011 x0013 NOP
x3166 0000000000010010 x0012 NOP
x3167 0000000000010001 x0011 NOP
x3168 0000000000010100 x0014 NOP
x3169 0000000000010001 x0011 NOP
x316A 0000000000010001 x0011 NOP
x316B 0000000000010011 x0013 NOP
x316C 0000000000010011 x0013 NOP
x316D 0000000000010010 x0012 NOP
x316E 0000000000010100 x0014 NOP
x316F 0000000000010010 x0012 NOP
x3170 0000000000010010 x0012 NOP
x3171 0000000000010011 x0013 NOP
x3172 0000000000010100 x0014 NOP
x3173 0000000000010011 x0013 NOP
x3174 0000000000010100 x0014 NOP
x3175 0000000000010011 x0013 NOP
x3176 0000000000010011 x0013 NOP
x3177 0000000000010011 x0013 NOP
x3178 0000000000010101 x0015 NOP
x3179 0000000000010100 x0014 NOP
x317A 0000000000010100 x0014 NOP
x317B 0000000000010100 x0014 NOP
x317C 0000000000010100 x0014 NOP
x317D 0000000000010011 x0013 NOP
x317E 0000000000010110 x0016 NOP
x317F 0000000000010101 x0015 NOP
x3180 0000000000010100 x0014 NOP
x3181 0000000000010101 x0015 NOP
x3182 0000000000010101 x0015 NOP
x3183 0000000000010011 x0013 NOP
x3184 0000000000010111 x0017 NOP
x3185 0000000000010110 x0016 NOP
x3186 0000000000010100 x0014 NOP
x3187 0000000000010110 x0016 NOP
x3188 0000000000010110 x0016 NOP
x3189 0000000000010011 x0013 NOP
x318A 0000000000011000 x0018 NOP
x318B 0000000000010111 x0017 NOP
x318C 0000000000010100 x0014 NOP
x318D 0000000000010111 x0017 NOP
x318E 0000000000010111 x0017 NOP
x318F 0000000000010100 x0014 NOP
x3190 0000000000011000 x0018 NOP
x3191 0000000000011000 x0018 NOP
x3192 0000000000000000 x0000 NOP
x3193 0000000000000000 x0000 NOP
x3194 0000000000000000 x0000 NOP
x3195 0000000000000000 x0000 NOP
x3196 0000000000000000 x0000 NOP
x3197 0000000000000000 x0000 NOP
x3198 0000000000000000 x0000 NOP
x3199 0000000000000000 x0000 NOP
x319A 0000000000000000 x0000 NOP
x319B 0000000000000000 x0000 NOP
x319C 0000000000000000 x0000 NOP
x319D 0000000000000000 x0000 NOP
x319E 0000000000000000 x0000 NOP
x319F 0000000000000000 x0000 NOP
选择静态分析汇编的话,最重要的一件事就是确定程序流程。不然寄存器的值绝对会乱。
程序输入flag后,连续有三块跳转,流程分别为:
- 0x3023 -> 0x3059 -> 0x3030 -> 0x3011
- 0x3035 -> 0x305b -> 0x3043 -> 0x3011
- 0x3048 -> 0x3061 -> 0x3055 -> 0x3011
然后说一下程序的几个数据:
-
0x30E4处的值是0x4000,这是flag存储的位置
-
0x30E5是0x18,flag的长度
-
0x30E6开始的0x18个数据就是flag的密文了
-
0x30FF开始的数据,每三个一组,分别记为a,b,c,a是操作码,可以是0x11,0x13,0x14,b和c是操作数。
前面提到过连续的三块跳转,其实就是三个操作码对应的case。当然你要是把0x30FF的数据提取出来,会发现根本没有0x11的操作码,所以第一个case其实从未执行过。
0x13 1 0
0x14 0 0
0x13 2 1
0x14 1 1
0x13 3 2
0x14 2 2
0x13 4 3
0x14 3 3
0x13 5 4
0x14 4 4
0x13 6 5
0x14 5 5
0x13 7 6
0x14 6 6
0x13 8 7
0x14 7 7
0x13 9 8
0x14 8 8
0x13 10 9
0x14 9 9
0x13 11 10
0x14 10 10
0x13 12 11
0x14 11 11
0x13 13 12
0x14 12 12
0x13 14 13
0x14 13 13
0x13 15 14
0x14 14 14
0x13 16 15
0x14 15 15
0x13 17 16
0x14 16 16
0x13 18 17
0x14 17 17
0x13 19 18
0x14 18 18
0x13 20 19
0x14 19 19
0x13 21 20
0x14 20 20
0x13 22 21
0x14 21 21
0x13 23 22
0x14 22 22
0x13 24 23
0x14 23 23
0x14 24 24
然后我们分别分析下三个case的逻辑吧。
- 0x11的case,对应0x3023的代码,flag[c] = b + flag[c]
- 0x13的case,对应0x3035的代码,flag[c] = (flag[b] & ~(flag[c])) + ((~flag[b]) & flag[c])
- 0x14的case,对应0x3048的代码,验证flag[b] == cipher[0x18 - c]
需要注意一点,有意思的是~n + 1表示的是n的相反数,所以m + (~n + 1)表示的是m-n,利用结果是否等于0,可以选择是否进行跳转(BRZ)
回到主要的逻辑上来,结合上面的0x30FF的数据,你会发现其实是类似这样的:
#a,b,c是0x30FF的第i组
for i in range(24):
flag[c] = (flag[b] & ~(flag[c])) + ((~flag[b]) & flag[c])
if flag[b] != cipher[0x18 - c]:
exit()
if flag[24] != cipher[24]:
exit()
print('正确')
那行等式我没想出怎么逆,好像也逆不了??所以直接爆破了。可以写出下面的脚本:
几个小时后的补充:
看了看队友的博客,他的脚本居然只有异或??
试了下,发现(~a & b) + (a & ~b) = a ^ b
,哇,居然还有这种化简。
其实仔细想想,确实是这样的。
因为a和~a的存在,导致针对具体的某一bit,(~a & b)和(a & ~b)二者必不可能同时为1,所以加法进位的问题不复存在。
不过脚本我就不改啦,你们自己写的时候就不用爆破了,直接用异或解就行。
code = '''x30E4 0100000000000000 x4000 JSRR R0
x30E5 0000000000011000 x0018 NOP
x30E6 0000000001101100 x006C NOP
x30E7 0000000000001111 x000F NOP
x30E8 0000000001010000 x0050 NOP
x30E9 0000000001101100 x006C NOP
x30EA 0000000001101110 x006E NOP
x30EB 0000000001000010 x0042 NOP
x30EC 0000000000101100 x002C NOP
x30ED 0000000000101100 x002C NOP
x30EE 0000000000011110 x001E NOP
x30EF 0000000000001100 x000C NOP
x30F0 0000000000001101 x000D NOP
x30F1 0000000000000000 x0000 NOP
x30F2 0000000000110011 x0033 NOP
x30F3 0000000000111101 x003D NOP
x30F4 0000000000010111 x0017 NOP
x30F5 0000000000000001 x0001 NOP
x30F6 0000000000101011 x002B NOP
x30F7 0000000000111100 x003C NOP
x30F8 0000000000001100 x000C NOP
x30F9 0000000000000010 x0002 NOP
x30FA 0000000000011101 x001D NOP
x30FB 0000000000011100 x001C NOP
x30FC 0000000000001001 x0009 NOP
x30FD 0000000000010001 x0011 NOP
x30FE 0000000000010001 x0011 NOP
x30FF 0000000000010011 x0013 NOP
x3100 0000000000000001 x0001 NOP
x3101 0000000000000000 x0000 NOP
x3102 0000000000010100 x0014 NOP
x3103 0000000000000000 x0000 NOP
x3104 0000000000000000 x0000 NOP
x3105 0000000000010011 x0013 NOP
x3106 0000000000000010 x0002 NOP
x3107 0000000000000001 x0001 NOP
x3108 0000000000010100 x0014 NOP
x3109 0000000000000001 x0001 NOP
x310A 0000000000000001 x0001 NOP
x310B 0000000000010011 x0013 NOP
x310C 0000000000000011 x0003 NOP
x310D 0000000000000010 x0002 NOP
x310E 0000000000010100 x0014 NOP
x310F 0000000000000010 x0002 NOP
x3110 0000000000000010 x0002 NOP
x3111 0000000000010011 x0013 NOP
x3112 0000000000000100 x0004 NOP
x3113 0000000000000011 x0003 NOP
x3114 0000000000010100 x0014 NOP
x3115 0000000000000011 x0003 NOP
x3116 0000000000000011 x0003 NOP
x3117 0000000000010011 x0013 NOP
x3118 0000000000000101 x0005 NOP
x3119 0000000000000100 x0004 NOP
x311A 0000000000010100 x0014 NOP
x311B 0000000000000100 x0004 NOP
x311C 0000000000000100 x0004 NOP
x311D 0000000000010011 x0013 NOP
x311E 0000000000000110 x0006 NOP
x311F 0000000000000101 x0005 NOP
x3120 0000000000010100 x0014 NOP
x3121 0000000000000101 x0005 NOP
x3122 0000000000000101 x0005 NOP
x3123 0000000000010011 x0013 NOP
x3124 0000000000000111 x0007 NOP
x3125 0000000000000110 x0006 NOP
x3126 0000000000010100 x0014 NOP
x3127 0000000000000110 x0006 NOP
x3128 0000000000000110 x0006 NOP
x3129 0000000000010011 x0013 NOP
x312A 0000000000001000 x0008 NOP
x312B 0000000000000111 x0007 NOP
x312C 0000000000010100 x0014 NOP
x312D 0000000000000111 x0007 NOP
x312E 0000000000000111 x0007 NOP
x312F 0000000000010011 x0013 NOP
x3130 0000000000001001 x0009 NOP
x3131 0000000000001000 x0008 NOP
x3132 0000000000010100 x0014 NOP
x3133 0000000000001000 x0008 NOP
x3134 0000000000001000 x0008 NOP
x3135 0000000000010011 x0013 NOP
x3136 0000000000001010 x000A NOP
x3137 0000000000001001 x0009 NOP
x3138 0000000000010100 x0014 NOP
x3139 0000000000001001 x0009 NOP
x313A 0000000000001001 x0009 NOP
x313B 0000000000010011 x0013 NOP
x313C 0000000000001011 x000B NOP
x313D 0000000000001010 x000A NOP
x313E 0000000000010100 x0014 NOP
x313F 0000000000001010 x000A NOP
x3140 0000000000001010 x000A NOP
x3141 0000000000010011 x0013 NOP
x3142 0000000000001100 x000C NOP
x3143 0000000000001011 x000B NOP
x3144 0000000000010100 x0014 NOP
x3145 0000000000001011 x000B NOP
x3146 0000000000001011 x000B NOP
x3147 0000000000010011 x0013 NOP
x3148 0000000000001101 x000D NOP
x3149 0000000000001100 x000C NOP
x314A 0000000000010100 x0014 NOP
x314B 0000000000001100 x000C NOP
x314C 0000000000001100 x000C NOP
x314D 0000000000010011 x0013 NOP
x314E 0000000000001110 x000E NOP
x314F 0000000000001101 x000D NOP
x3150 0000000000010100 x0014 NOP
x3151 0000000000001101 x000D NOP
x3152 0000000000001101 x000D NOP
x3153 0000000000010011 x0013 NOP
x3154 0000000000001111 x000F NOP
x3155 0000000000001110 x000E NOP
x3156 0000000000010100 x0014 NOP
x3157 0000000000001110 x000E NOP
x3158 0000000000001110 x000E NOP
x3159 0000000000010011 x0013 NOP
x315A 0000000000010000 x0010 NOP
x315B 0000000000001111 x000F NOP
x315C 0000000000010100 x0014 NOP
x315D 0000000000001111 x000F NOP
x315E 0000000000001111 x000F NOP
x315F 0000000000010011 x0013 NOP
x3160 0000000000010001 x0011 NOP
x3161 0000000000010000 x0010 NOP
x3162 0000000000010100 x0014 NOP
x3163 0000000000010000 x0010 NOP
x3164 0000000000010000 x0010 NOP
x3165 0000000000010011 x0013 NOP
x3166 0000000000010010 x0012 NOP
x3167 0000000000010001 x0011 NOP
x3168 0000000000010100 x0014 NOP
x3169 0000000000010001 x0011 NOP
x316A 0000000000010001 x0011 NOP
x316B 0000000000010011 x0013 NOP
x316C 0000000000010011 x0013 NOP
x316D 0000000000010010 x0012 NOP
x316E 0000000000010100 x0014 NOP
x316F 0000000000010010 x0012 NOP
x3170 0000000000010010 x0012 NOP
x3171 0000000000010011 x0013 NOP
x3172 0000000000010100 x0014 NOP
x3173 0000000000010011 x0013 NOP
x3174 0000000000010100 x0014 NOP
x3175 0000000000010011 x0013 NOP
x3176 0000000000010011 x0013 NOP
x3177 0000000000010011 x0013 NOP
x3178 0000000000010101 x0015 NOP
x3179 0000000000010100 x0014 NOP
x317A 0000000000010100 x0014 NOP
x317B 0000000000010100 x0014 NOP
x317C 0000000000010100 x0014 NOP
x317D 0000000000010011 x0013 NOP
x317E 0000000000010110 x0016 NOP
x317F 0000000000010101 x0015 NOP
x3180 0000000000010100 x0014 NOP
x3181 0000000000010101 x0015 NOP
x3182 0000000000010101 x0015 NOP
x3183 0000000000010011 x0013 NOP
x3184 0000000000010111 x0017 NOP
x3185 0000000000010110 x0016 NOP
x3186 0000000000010100 x0014 NOP
x3187 0000000000010110 x0016 NOP
x3188 0000000000010110 x0016 NOP
x3189 0000000000010011 x0013 NOP
x318A 0000000000011000 x0018 NOP
x318B 0000000000010111 x0017 NOP
x318C 0000000000010100 x0014 NOP
x318D 0000000000010111 x0017 NOP
x318E 0000000000010111 x0017 NOP
x318F 0000000000010100 x0014 NOP
x3190 0000000000011000 x0018 NOP
x3191 0000000000011000 x0018 NOP '''
import re
lines = code.split('\n')
data = []
for line in lines:
r = re.search(r'x[0-9a-fA-F]{4} *?\d{16} *?x[0-9a-fA-F]{2}([0-9a-fA-F]{2})', line)
data.append(int(r.group(1), 16))
cipher = data[2:27]
'''
op = data[27:]
for i in range(len(op)//3):
t = op[i*3:i*3+3]
a, b, c = t[0], t[1], t[2]
#print(hex(a), b, c)
'''
flag = [0] * 25
flag[24] = cipher[0x18 - 24]
for i in range(23, -1, -1):
for j in range(32, 127):
if cipher[0x18 - i] == (flag[i+1] & (~j)) + ((~flag[i+1]) & j):
flag[i] = j
#print(j,end= ' ')
print()
print(flag[::-1])
print(''.join(map(chr, flag[::-1])))
Misc
GACTF FeedBack
问卷,直接拍主办方马屁即可。
trihistory
给出一个docker,运行后发现只有80端口开放。端口转发一下并访问网站,就一个普通的html。
docker run -it -p 50050:80 impakho/trihistory
exec进入容器内部docker exec -it (容器ID) /bin/bash
find / -name flag
发现一个flag.html,但是它说flag已经删了。可以想到docker文件恢复。
首先docker history --no-trunc (容器ID)
看看操作历史(输出结果不好排版,所以我就不粘贴了),然后docker inspect (容器ID)
显示镜像详情。
[root@izwdpnodbapihwz ~]# docker inspect f8
[
{
"Id": "sha256:f8f0608cd1a4334c15aa7f37598f5aa1ba7aca9556897a1d119a2e8432424238",
"RepoTags": [
"impakho/trihistory:latest"
],
"RepoDigests": [
"impakho/trihistory@sha256:17297590f715c03d277b0587bedfd471b1cef1270903751c978e72dd0de570f5"
],
"Parent": "",
"Comment": "",
"Created": "2020-05-20T10:57:23.1669636Z",
"Container": "1d4ee6c290809d39f5c3b9796d35db94a128ed59cb146fc07ff8bbad529ba4a8",
"ContainerConfig": {
"Hostname": "1d4ee6c29080",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"80/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"ENTRYPOINT [\"/start.sh\"]"
],
"ArgsEscaped": true,
"Image": "sha256:eea8459418cdd2ad3e0ce40ac4b828a62eedc4d654bc7af9ff8cf528b8ebec09",
"Volumes": null,
"WorkingDir": "/",
"Entrypoint": [
"/start.sh"
],
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "18.06.1-ce",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"80/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": null,
"ArgsEscaped": true,
"Image": "sha256:eea8459418cdd2ad3e0ce40ac4b828a62eedc4d654bc7af9ff8cf528b8ebec09",
"Volumes": null,
"WorkingDir": "/",
"Entrypoint": [
"/start.sh"
],
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 158201380,
"VirtualSize": 158201380,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/2f7214b86ceab0536712adb11af6a68719533e2a9221f54df0302d5aa3e26e37/diff:/var/lib/docker/overlay2/e84985e750d316e6239f05939c7ada004483cb539512379c7ac9eef00692980e/diff:/var/lib/docker/overlay2/727fd216638fe9de4331070a077f6f649b8cf66f57126967f317b6424ec56581/diff:/var/lib/docker/overlay2/4d171d3ce743841b0734f25fde902b4d3bf18bb3c7183d2593549fe555ab23aa/diff:/var/lib/docker/overlay2/39bcdfc0de7f149254ba02f2dd3ac61b20167953268a6989f3b4e9e5997533b3/diff:/var/lib/docker/overlay2/0f06c00bcdf99960a4488995f31203f57be0ad2c7180feb5f6ce22eabe143702/diff:/var/lib/docker/overlay2/ebd1261fadfad7d548bdf7ebcff5d5c67e2d0bd85693e2a322d2a8a71e4d7c86/diff:/var/lib/docker/overlay2/88c0f970c53e169fd89da0d622d8604a45aec80c7221b59dce917e7867c58f14/diff:/var/lib/docker/overlay2/b6b397a4be86157bf545028bbb3fa51445e0263577bb516cebe041e86305cd13/diff",
"MergedDir": "/var/lib/docker/overlay2/962c512dbe97a4da4ede6833e4796ce80ddf8de8f9322b4cee94820e46447427/merged",
"UpperDir": "/var/lib/docker/overlay2/962c512dbe97a4da4ede6833e4796ce80ddf8de8f9322b4cee94820e46447427/diff",
"WorkDir": "/var/lib/docker/overlay2/962c512dbe97a4da4ede6833e4796ce80ddf8de8f9322b4cee94820e46447427/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e",
"sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6",
"sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794",
"sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233",
"sha256:8108c9bd0bf43db0fed516a8f8484c2ecd938ec9bd8ea1334b88b9ef8bdf8053",
"sha256:ca6b45f562603630ba96c849823ac1f1b4be17fe95899ba7ee817f24590e9c19",
"sha256:4c2307ccb6c66b7ee5b0df2b28ace1c53dd52f834adaa30606450393ef28fee6",
"sha256:343896badf0a77e212b0ff3e05c67b6bc6fef467bc83e519fa1b4f8059d1a6bd",
"sha256:f41e1512553f003a733275dcd77494c67c5eda32d9ce5fee8d680c9877b2598c",
"sha256:af63a460580b4b088fb3a4bd2d9a9c7eae28621844a1df10b5c2aa9bfc9db93d"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
注意上面信息中的:
"LowerDir": "/var/lib/docker/overlay2/2f7214b86ceab0536712adb11af6a68719533e2a9221f54df0302d5aa3e26e37/diff:/var/lib/docker/overlay2/e84985e750d316e6239f05939c7ada004483cb539512379c7ac9eef00692980e/diff:/var/lib/docker/overlay2/727fd216638fe9de4331070a077f6f649b8cf66f57126967f317b6424ec56581/diff:/var/lib/docker/overlay2/4d171d3ce743841b0734f25fde902b4d3bf18bb3c7183d2593549fe555ab23aa/diff:/var/lib/docker/overlay2/39bcdfc0de7f149254ba02f2dd3ac61b20167953268a6989f3b4e9e5997533b3/diff:/var/lib/docker/overlay2/0f06c00bcdf99960a4488995f31203f57be0ad2c7180feb5f6ce22eabe143702/diff:/var/lib/docker/overlay2/ebd1261fadfad7d548bdf7ebcff5d5c67e2d0bd85693e2a322d2a8a71e4d7c86/diff:/var/lib/docker/overlay2/88c0f970c53e169fd89da0d622d8604a45aec80c7221b59dce917e7867c58f14/diff:/var/lib/docker/overlay2/b6b397a4be86157bf545028bbb3fa51445e0263577bb516cebe041e86305cd13/diff"
分别去这几个路径看看。
其中有一个路径中包含着一个git项目。
然后导入到本地,发现git的历史中有.flag.html.swp
那就进行版本回滚吧。
D:\桌面\root - 副本\history>git log commit a6ed84884a71afaa7a4e34f1b46af69cc773d6ce (HEAD -> master) Author: impakho <pakho@sent.com> Date: Wed May 20 18:38:07 2020 +0800 add w3.css commit 4f19a2121a27dc54d85408b99a04d14e6424aacf Author: impakho <pakho@sent.com> Date: Wed May 20 18:27:52 2020 +0800 update init.sh commit e9418116088aefc0d7238d32cd96f0f3d36a0fc1 Author: impakho <pakho@sent.com> Date: Wed May 20 16:56:41 2020 +0800 remove file commit 47a5ffbd63f271bc627af973d7a949232cfb47c6 Author: impakho <pakho@sent.com> Date: Wed May 20 16:55:57 2020 +0800 add wwwroot commit 40954a24d572eff1ecf97257ec96baa899addeb4 Author: impakho <pakho@sent.com> Date: Wed May 20 16:29:38 2020 +0800 init commit
D:\桌面\root - 副本\history>git revert e9418116088aefc0d7238d32cd96f0f3d36a0fc1 [master cf3da41] Revert "remove file"
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 wwwroot/.flag.html.swp
拿到.flag.html.swp
,打开后在末尾发现flag。
参考:
capture
提取坐标:
import re
with open(r'captured (1).txt', 'r')as f:
text = f.read()
lines = text.split()
with open('capout.txt', 'w')as f:
for line in lines:
r = re.search(r',(\d+?),(\d+?)$', line)
if r:
#print(r.group(1), r.group(2))
#out += r.group(1) + ' ' + r.group(2) + '\n'
f.write(r.group(1) + ' ' + r.group(2) + '\n')
else:
r = re.search(r'U(\d+?),(\d+?)$', line)
if r:
f.write(r.group(1) + ' ' + r.group(2) + '\n')
else:
r = re.search(r'D(\d+?),(\d+?)$', line)
if r:
f.write(r.group(1) + ' ' + r.group(2) + '\n')
然后kali下用gnuplot画图,这个需要选取合适的散点的大小和连线的粗细,不然很难分别出字母。
我用的是plot "capout.txt" with linespoints lw 1 pt 7 ps 0.3
lw是线的宽度,ps是点的大小,pt是点线类型,可以参考:
绘制出
用photoshop顺时针旋转180度,并进行合适的拉伸和压缩,如果看不清的话可以考虑锐化。
最终好不容易调出这么张勉强能分辨flag的图片:
有的字母真的不好分辨,自己慢慢调吧,我调了五六张。
gactf{33ffb710eaae052d8b2f7a3955b6517c}
参考:gnuplot下画图以及设置点、线基础
oldmodem
首先安装minimodem:
Ubuntu installation:
sudo add-apt-repository ppa:kamalmostafa/minimodem
sudo apt-get update
sudo apt-get install minimodem
Debian installation:
sudo apt-get install minimodem
Fedora installation:
sudo yum install minimodem
然后直接一行指令就可以拿到flag:
minimodem -r -f encoded 1200 > output
bell202是1200Hz。
flag就在output的文末
参考: