GACTF的几道逆向和MISC
本帖最后由 iyzyi 于 2020-9-1 15:03 编辑## RE
### checkin
题目说推荐虚拟机做。
首先尝试xp,结果报错,报错信息中意外得知这是调用的ruby.exe。
然后试了下win7,可以正常运行。
如果输入flag的时候,不输入,直接回车,也会有下面的报错:
所以直接来到报错中出现的目录下,找到ruby脚本。
注意程序运行完之后会删除上面解压出来的那个目录,所以运行程序后,停在输入flag的那一步,接着去找上面的目录中的ruby脚本。
虚拟机没安装vmware,直接把ruby脚本截个图吧:
然后在线解aes就可以了。
队友用了一个叫processmonitor的工具,比我这碰巧遇到报错信息的方法要高明的多,欢迎去看一下[他的题解](https://ljzjsc.com/index.php/archives/85/#0x2checkin)。
### EasyRe
一个vm。
动调来到vm指令的相关代码处,并分析各个操作码的含义:
```c
int __cdecl sub_8048838(_DWORD *a1)
{
int v1; // ecx
_BYTE *v2; // ST28_4
int result; // eax
unsigned int v4; // et1
unsigned int v5; //
v5 = __readgsdword(0x14u);
while ( 1 )
{
if ( *(_BYTE *)a1 == 113 ) // 没用到
{
a1 -= 4;
*(_DWORD *)a1 = *(_DWORD *)(a1 + 1);
a1 += 5;
}
if ( *(_BYTE *)a1 == 65 ) // a1 += a1
{
a1 += a1;
++a1;
}
if ( *(_BYTE *)a1 == 66 ) // a1 -= a1
{
a1 -= a1;
++a1;
}
if ( *(_BYTE *)a1 == 67 ) // a1 *= a1
{
a1 *= a1;
++a1;
}
if ( *(_BYTE *)a1 == 68 ) // a1 /= a1
{
a1 /= a1;
++a1;
}
if ( *(_BYTE *)a1 == 128 ) // op ? (int)num a1 = num opn += 6
{
a1 = *(_DWORD *)(a1 + 2);
a1 += 6;
}
if ( *(_BYTE *)a1 == 119 ) // a1 ^= a1
{
a1 ^= a1;
++a1;
}
if ( *(_BYTE *)a1 == 83 ) // 没用到
{
sub_80485F0(*(char *)a1);
a1 += 2;
}
if ( *(_BYTE *)a1 == 34 ) // a1 >>= a1
{
v1 = a1;
a1 >>= v1;
++a1;
}
if ( *(_BYTE *)a1 == 35 ) // a1 <<= a1
{
v1 = a1;
a1 <<= v1;
++a1;
}
if ( *(_BYTE *)a1 == 153 ) // 跳出循环
break;
if ( *(_BYTE *)a1 == 118 ) // 没用到
{
a1 = *(_DWORD *)a1;
*(_DWORD *)a1 = 0;
a1 += 4;
a1 += 5;
}
if ( *(_BYTE *)a1 == 84 ) // 没用到
{
v2 = (_BYTE *)a1;
*v2 = sub_8048580();
a1 += 2;
}
if ( *(_BYTE *)a1 == 48 ) // a1 |= a1
{
a1 |= a1;
++a1;
}
if ( *(_BYTE *)a1 == 49 ) // a1 &= a1
{
a1 &= a1;
++a1;
}
if ( *(_BYTE *)a1 == 9 ) //a1 = 输入int64
{
a1 = dword_804B28C;
++a1;
}
if ( *(_BYTE *)a1 == 16 ) // a1 = a1
{
a1 = a1;
++a1;
}
if ( *(_BYTE *)a1 == 17 ) // printf("%p\n", a1)
{
printf((const char *)&unk_804920C, a1);
++a1;
}
if ( *(_BYTE *)a1 == 160 ) // if (a1 == 0x26F8D100) opn++ else exit()
{
if ( a1 == 653840640 )
++a1;
else
exit();
}
if ( *(_BYTE *)a1 == 161 ) // 输入flag, flag = byte_804B2E0
{
printf("flag:");
sub_8048560(0, (int)byte_804B2E0, 40);
if ( strlen((int)byte_804B2E0) != 33 )
exit();
++a1;
}
if ( *(_BYTE *)a1 == 177 ) // a1 = dword_804B2A0
{
a1 = dword_804B2A0;
++a1;
}
if ( *(_BYTE *)a1 == 178 ) // a1 = dword_804B2A4
{
a1 = dword_804B2A4;
++a1;
}
if ( *(_BYTE *)a1 == 164 ) // op byte(num) ? ? dword_804B2A0 = a1 opn += 4(后两字节无效)
{
dword_804B2A0[*(unsigned __int8 *)(a1 + 1)] = a1;
a1 += 4;
}
if ( *(_BYTE *)a1 == 179 ) // a1 = dword_804B2A8
{
a1 = dword_804B2A8;
++a1;
}
if ( *(_BYTE *)a1 == 180 ) // a1 = dword_804B2AC
{
a1 = dword_804B2AC;
++a1;
}
if ( *(_BYTE *)a1 == 193 ) // op byte(num) a1 = byte_804B2E0 opn += 2
{
a1 = byte_804B2E0[*(unsigned __int8 *)(a1 + 1)];
a1 += 2;
}
if ( *(_BYTE *)a1 == 194 ) // op (int)num if (a1 == num) opn += 5
{
if ( a1 != *(_DWORD *)(a1 + 1) )
exit();
a1 += 5;
}
}
v4 = __readgsdword(0x14u);
result = v4 ^ v5;
if ( v4 != v5 )
result = sub_8048590(v1);
return result;
}
```
同样是动调拿到vm的代码,并dump出来,然后用下面的脚本分析vm:
```python
dic = [
(65, 'a1 += a1', 1),
(66, 'a1 -= a1', 1),
(67, 'a1 *= a1', 1),
(68, 'a1 /= a1', 1),
(128, 'a1[?] = %d', 6),
(119, 'a1 ^= a1', 1),
(34, 'a1 >>= a1', 1),
(35, 'a1 <<= a1', 1),
(153, '跳出循环', 1),
(48, 'a1 |= a1', 1),
(49, 'a1 &= a1', 1),
(9, 'a1 = 输入int', 1),
(16, 'a1 = a1', 1),
(17, 'printf("%p\n", a1)', 1),
(160, 'if (a1 == 0x26F8D100) opn++ else exit()', 1),
(161, '输入flag, flag = byte_804B2E0', 1),
(177, 'a1 = dword_804B2A0', 1),
(178, 'a1 = dword_804B2A4', 1),
(164, 'dword_804B2A0[%d] = a1', 4),
(179, 'a1 = dword_804B2A8', 1),
(180, 'a1 = dword_804B2AC', 1),
(193, 'a1 = byte_804B2E0[%d]', 2),
(194, 'if (a1 == %d)', 5)
]
def get_int(b):
import struct
return struct.unpack('I', b)
with open('dump', 'rb')as f:
b = f.read()
opn = 0
while (True):
op = b
for i in range(len(dic)):
if op == dic:
code = dic
if op == 128:
num = get_int(b)
print(code % num)
elif op == 164 or op == 193:
num = b
print(code % num)
elif op == 194:
num = get_int(b)
print(code % num)
else:
print(code)
opn += dic
break
```
分析输出的结果:
```c
a1 = 输入int
a1 = a1
a1 = 13
a1 >>= a1
a1 ^= a1 //a1 = a1 ^ (a1 >> 13)
a1 = a1 //a1 = a1
a1 = 9
a1 <<= a1
a1 = 2029229568
a1 &= a1
a1 ^= a1 //a1 = ((a1 << 9) & 0x78f39600) ^ a1
a1 = a1 //a1 = a1
a1 = 17
a1 <<= a1
a1 = 2245263360
a1 &= a1
a1 ^= a1 //a1 = ((a1 << 17) & 0x85d40000) ^ a1
a1 = a1 //a1 = a1
a1 = 19
a1 >>= a1
a1 ^= a1 //a1 = (a1 >> 19) ^ a1
if (a1 == 0x26F8D100) opn++ else exit()
a1 = 输入int
a1[?] = 255
a1 &= a1
a1[?] = 2
a1 *= a1
a1[?] = 24
a1 += a1
dword_804B2A0 = a1 // (a1 & 255) * 2 + 24
a1 = 输入int
a1[?] = 8
a1 >>= a1
a1[?] = 255
a1 &= a1
a1[?] = 7
a1 /= a1
a1[?] = 33
a1 += a1
dword_804B2A0 = a1 // ((a1 >> 8) & 255) / 7 + 33
a1 = 输入int
a1[?] = 16
a1 >>= a1
a1[?] = 255
a1 &= a1
a1[?] = 187
a1 ^= a1
a1[?] = 255
a1 += a1
dword_804B2A0 = a1 // (((a1 >> 16) & 255) ^ 187) + 255
a1 = 输入int
a1[?] = 24
a1 >>= a1
a1[?] = 255
a1 &= a1
a1[?] = 160
a1 -= a1
a1[?] = 119
a1 += a1
dword_804B2A0 = a1 // ((a1 >> 24) & 255) - 160 + 119
输入flag, flag = byte_804B2E0
a1 = byte_804B2E0
a1 = dword_804B2A0
a1 ^= a1
if (a1 == 267) // if (flag ^ dword_804B2A0 == 267)
a1 = byte_804B2E0
a1 = dword_804B2A4
a1 ^= a1
if (a1 == 122) // if (flag ^ dword_804B2A0 == 122)
a1 = byte_804B2E0
a1 = dword_804B2AC
a1 ^= a1
if (a1 == 149) // if (flag ^ dword_804B2A0 == 149)
a1 = byte_804B2E0
a1 = dword_804B2A8
a1 ^= a1
if (a1 == 262) // if (flag ^ dword_804B2A0 == 262)
a1 = byte_804B2E0
a1 = dword_804B2A4
a1 ^= a1
if (a1 == 125) // if (flag ^ dword_804B2A0 == 125)
a1 = byte_804B2E0
a1 = dword_804B2AC
a1 ^= a1
if (a1 == 173)
a1 = byte_804B2E0
a1 = dword_804B2A0
a1 ^= a1
if (a1 == 303)
a1 = byte_804B2E0
a1 = dword_804B2A8
a1 ^= a1
if (a1 == 357)
a1 = byte_804B2E0
a1 = dword_804B2A0
a1 ^= a1
if (a1 == 301)
a1 = byte_804B2E0
a1 = dword_804B2A0
a1 ^= a1
if (a1 == 303)
a1 = byte_804B2E0
a1 = dword_804B2A8
a1 ^= a1
if (a1 == 313)
a1 = byte_804B2E0
a1 = dword_804B2A8
a1 ^= a1
if (a1 == 269)
a1 = byte_804B2E0
a1 = dword_804B2AC
a1 ^= a1
if (a1 == 187)
a1 = byte_804B2E0
a1 = dword_804B2A4
a1 ^= a1
if (a1 == 8)
a1 = byte_804B2E0
a1 = dword_804B2A8
a1 ^= a1
if (a1 == 269)
a1 = byte_804B2E0
a1 = dword_804B2A0
a1 ^= a1
if (a1 == 319)
a1 = byte_804B2E0
a1 = dword_804B2A8
a1 ^= a1
if (a1 == 314)
a1 = byte_804B2E0
a1 = dword_804B2A8
a1 ^= a1
if (a1 == 353)
a1 = byte_804B2E0
a1 = dword_804B2A4
a1 ^= a1
if (a1 == 87)
a1 = byte_804B2E0
a1 = dword_804B2A0
a1 ^= a1
if (a1 == 288)
a1 = byte_804B2E0
a1 = dword_804B2A8
a1 ^= a1
if (a1 == 269)
a1 = byte_804B2E0
a1 = dword_804B2A0
a1 ^= a1
if (a1 == 319)
a1 = byte_804B2E0
a1 = dword_804B2A8
a1 ^= a1
if (a1 == 319)
a1 = byte_804B2E0
a1 = dword_804B2AC
a1 ^= a1
if (a1 == 181)
a1 = byte_804B2E0
a1 = dword_804B2A0
a1 ^= a1
if (a1 == 275)
a1 = byte_804B2E0
a1 = dword_804B2AC
a1 ^= a1
if (a1 == 160)
a1 = byte_804B2E0
a1 = dword_804B2A0
a1 ^= a1
if (a1 == 289)
a1 = byte_804B2E0
a1 = dword_804B2A8
a1 ^= a1
if (a1 == 269)
a1 = byte_804B2E0
a1 = dword_804B2A4
a1 ^= a1
if (a1 == 11)
a1 = byte_804B2E0
a1 = dword_804B2A8
a1 ^= a1
if (a1 == 313)
a1 = byte_804B2E0
a1 = dword_804B2A0
a1 ^= a1
if (a1 == 371)
a1 = byte_804B2E0
a1 = dword_804B2A4
a1 ^= a1
if (a1 == 70)
跳出循环
```
可以看出首先是输入一个数,依次经过下面的运算后判断是否和 0x26F8D100相等。
```
a1 = a1 ^ (a1 >> 13)
a1 = ((a1 << 9) & 0x78f39600) ^ a1
a1 = ((a1 << 17) & 0x85d40000) ^ a1
a1 = (a1 >> 19) ^ a1
```
很巧的是,前几天的七夕,我闲得没事干,随手写了个加解密的小程序,关键逻辑简直和本题的一模一样,我是万万没想到啊。
文章发在了看雪上,[一个有趣的加密小算法及其逆向](https://bbs.pediy.com/thread-261646.htm),里面有分析这个类型的算式如何逆向,同时做了一定的推广,也提供了加解密的c语言代码(本题甚至可以直接把我那篇文章提供的c代码修改一下即可)。建议大家先去看一下。
有一点不同的是,本题多了个 `& 0x78f39600`。其实不过是稍微进一步的拓展而已,看完上面的那篇博文,你应该能够想明白这个应该怎么处理。如果不明白,那么将下面的脚本和上面提到的我的那篇博文中的脚本对比下差异,就应该会懂了。
下面的脚本修改自上面提到的我的那篇博文,可以求出这个输入的数来:
```c
#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搞,不过我没试过,不太清楚具体行不行。
后面的逻辑就很简单了,直接写脚本:
```python
a = 4293442714
a = 0xffe8bc9a
l = * 4
l = (a & 255) * 2 + 24
l = ((a >> 8) & 255) // 7 + 33
l = (((a >> 16) & 255) ^ 187) + 255
l = ((a >> 24) & 255) - 160 + 119
print(l)
flag = * 32
flag = l ^ 267
flag = l ^ 122
flag = l ^ 149
flag = l ^ 262
flag = l ^ 125
flag = l ^ 173
flag = l ^ 303
flag = l ^ 357
flag = l ^ 301
flag = l ^ 303
flag = l ^ 313
flag = l ^ 269
flag = l ^ 187
flag = l ^ 8
flag = l ^ 269
flag = l ^ 319
flag = l ^ 314
flag = l ^ 353
flag = l ^ 87
flag = l ^ 288
flag = l ^ 269
flag = l ^ 319
flag = l ^ 319
flag = l ^ 181
flag = l ^ 275
flag = l ^ 160
flag = l ^ 289
flag = l ^ 269
flag = l ^ 11
flag = l ^ 313
flag = l ^ 371
flag = l ^ 70
print(flag)
print(''.join(map(chr, flag)))
```
### WannaFlag
本题文本框内开玩笑说6666RMB联系出题人买密钥,我闲得慌,还真去加了haivk大佬的QQ,哈哈。
界面看着很炫酷,其实不看花里胡哨的东西的话,逻辑炒鸡简单,签到题难度。
别跑偏了,不需要你看懂那个解密函数。只需要看sub_402280的关键代码:
上图黄框中的代码也不需要看,不要想复杂了。密钥长度不会超过64的,直接看后面的一小段即可。
加解密需要用到v38,v38与v37有关,而v37的值我们不清楚到底是啥意思,但好在v37的取值是0~6,所以爆破即可。
后面一小段的逻辑就是签到题难度,应该不需要我多说什么吧。
```python
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 = * 32
for i in range(32):
v58 = __ROR1__(b, i) ^ byte_420AE0
v58_2 = * 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 = v38 ^ v58
print(v58_2)
a =
print(''.join(map(chr, a)))
```
当然赛后完全可以再翻出解密函数来学习一波。
读入flag.bin:
创建一个CS模块中的密钥容器:
创建一个hash对象,0x8004表示采用的散列算法是SHA。等下生成key时,要用到这个hash对象:
计算密钥散列:
生成密钥,0x6801表示加密算法为RC4:
解密数据,写入文件:
归纳一下就是:
1. (https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontextw)生成CSP句柄
2. (https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptcreatehash)创建hash对象,第二个参数指定散列算法
3. (https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-crypthashdata)计算密钥的散列,第一个参数是上一步生成的hash对象
4. (https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptderivekey)生成密钥,第二个参数指定加密算法(是的,加密算法是在这一步指定的),第三个参数就是前面生成的散列对象。与之类似的还有个(https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptgenkey),不过这个是随机生成密钥而非指定。
5. (https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdecrypt)解密
6. 除此之外还有(https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptreleasecontext)释放CSP句柄,(https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdestroykey)释放密钥句柄,(https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-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。
然后慢慢分析吧(建议把下面的分析复制到本地再看),我觉得已经炒鸡详细了,几乎每一步都注释了。当然量太大了,错误在所难免,不过应该不会影响理解。
```asm
Registers:
R0 x00000
R1 x00000
R2 x00000
R3 x00000
R4 x00000
R5 x00000
R6 x00000
R7 x00000
PC x300012288
IR x00000
CC Z
Memory:
x30001110000001111010xE07A LEA R0, x307B ;WELCOME TO WORLD OF LC3
x30011111000000100010xF022 TRAP PUTS
x30020010000001110111x2077 LD R0, x307A ;0x0A,换行
x30031111000000100001xF021 TRAP OUT
x30041110000010010010xE092 LEA R0, x3097 ;PLEASE INPUT YOUR FLAG:
x30051111000000100010xF022 TRAP PUTS
x30060010011011011110x26DE LD R3, x30E5 ;R3 = = 0x18 ;flag长度
x30071111000000100000xF020 TRAP GETC ;从缓冲区接收一个字符
x30081111000000100001xF021 TRAP OUT ;输出这个字符
x30090010001011011010x22DA LD R1, x30E4 ;R1 = = 0x4000
x300A0001001001000011x1243 ADD R1, R1, R3 ;R1 = R1 + R3
x300B0111000001000000x7040 STR R0, R1, #0 ; = R0 ; = R0,字符串存储在0x4000
x300C0001011011111111x16FF ADD R3, R3, #-1 ;R3 = R3 - 1 ;所以输入后的字符串的存储是倒序的
x300D0000100000000001x0801 BRN x300F
x300E0000111111111000x0FF8 BRNZPx3007
x300F1110100011101111xE8EF LEA R4, x30FF ;R4 = 0x30FF
x30100101010010100000x54A0 AND R2, R2, #0 ;R2 = 0
x30110001001010000100x1284 ADD R1, R2, R4 ;R1 = 0x30FF + R2
x30120110001001000000x6240 LDR R1, R1, #0 ;R1 = =
x30130101000000100000x5020 AND R0, R0, #0 ;R0 = 0
x30140010000001100010x2062 LD R0, x3077 ;R0 =
x30151001000000111111x903F NOT R0, R0 ;R0 = ~R0 = ~
x30160001000000100001x1021 ADD R0, R0, #1 ;R0 = ~ + 1
x30170001000001000000x1040 ADD R0, R1, R0 ;R0 = + (~ + 1) = -
x30180000010000001010x040A BRZ x3023 ;意思是若R0等于0( == = 0x11),则一直跳转到0x3023
x30190010000001011110x205E LD R0, x3078
x301A1001000000111111x903F NOT R0, R0
x301B0001000000100001x1021 ADD R0, R0, #1
x301C0001000001000000x1040 ADD R0, R1, R0
x301D0000010000010111x0417 BRZ x3035 ; == = 0x13
x301E0010000001011010x205A LD R0, x3079
x301F1001000000111111x903F NOT R0, R0
x30200001000000100001x1021 ADD R0, R0, #1
x30210001000001000000x1040 ADD R0, R1, R0
x30220000010000100101x0425 BRZ x3048 ; == = 0x14
x30230001001010100001x12A1 ADD R1, R2, #1 ;R1 = R2 + 1
x30240001001100000001x1301 ADD R1, R4, R1 ;R1 = R4 + R2 + 1 ;R4 = 0x30FF
x30250110001001000000x6240 LDR R1, R1, #0 ;R1 =
x30260001110001100000x1C60 ADD R6, R1, #0 ;R6 = R1
x30270001001010100010x12A2 ADD R1, R2, #2 ;R1 = R2 + 2
x30280001001100000001x1301 ADD R1, R4, R1 ;R1 = R4 + (R2 + 2)
x30290110001001000000x6240 LDR R1, R1, #0 ;R1 =
x302A0010000010111001x20B9 LD R0, x30E4 ;R0 = ;flag基址0x4000
x302B0001000001100000x1060 ADD R0, R1, #0 ;R0 = +
x302C0110000000000000x6000 LDR R0, R0, #0 ;R0 = [ + ] = flag[]
x302D0001111000100000x1E20 ADD R7, R0, #0 ;R7 = flag[]
x302E0001101001100000x1A60 ADD R5, R1, #0 ;R5 =
x302F0000111000101001x0E29 BRNZPx3059
x30300010001010110011x22B3 LD R1, x30E4 ;R1 = = 0x4000
x30310001001101000001x1341 ADD R1, R5, R1 ;R1 = 0x4000 +
x30320111000001000000x7040 STR R0, R1, #0 ; = R0 ;flag[] = + flag[]
x30330001010010100011x14A3 ADD R2, R2, #3 ;R2 += 3
x30340000111111011100x0FDC BRNZPx3011
x30350001001010100001x12A1 ADD R1, R2, #1 ;R1 = R2 + 1
x30360001001100000001x1301 ADD R1, R4, R1 ;R1 = R4 + R2 + 1
x30370110001001000000x6240 LDR R1, R1, #0 ;R1 =
x30380010000010101011x20AB LD R0, x30E4 ;R0 = 0x4000
x30390001000000000001x1001 ADD R0, R0, R1 ;R0 = 0X4000 +
x303A0110110000000000x6C00 LDR R6, R0, #0 ;R6 = = FLAG[]
x303B0001001010100010x12A2 ADD R1, R2, #2 ;R1 = R2 + 2
x303C0001001100000001x1301 ADD R1, R4, R1 ;R1 = R4 + R1 = R4 + R2 + 2
x303D0110001001000000x6240 LDR R1, R1, #0 ;R1 =
x303E0010000010100101x20A5 LD R0, x30E4 ;R0 = 0X4000
x303F0001000000000001x1001 ADD R0, R0, R1 ;R0 = 0X4000 +
x30400001101001100000x1A60 ADD R5, R1, #0 ;R5 =
x30410110111000000000x6E00 LDR R7, R0, #0 ;R7 = ] = FLAG[]
x30420000111000011000x0E18 BRNZPx305B
x30430010001010100000x22A0 LD R1, x30E4 ;R1 = 0X4000
x30440001001001000101x1245 ADD R1, R1, R5 ;R1 = 0X4000 +
x30450111000001000000x7040 STR R0, R1, #0 ; = R0 ;FLAG[] = ((FLAG[]) & (~(FLAG[]))) + ((~FLAG[]) & (FLAG[]))
x30460001010010100011x14A3 ADD R2, R2, #3 ;R2 = R2 + 3
x30470000111111001001x0FC9 BRNZPx3011
x30480001001010100001x12A1 ADD R1, R2, #1 ;R1 = R2 + 1
x30490001001100000001x1301 ADD R1, R4, R1 ;R1 = R4 + R2 + 1
x304A0110001001000000x6240 LDR R1, R1, #0 ;R1 =
x304B0001110001100000x1C60 ADD R6, R1, #0 ;R6 = R1 =
x304C0001001010100010x12A2 ADD R1, R2, #2 ;R1 = R2 + 2
x304D0001001100000001x1301 ADD R1, R4, R1 ;R1 = R4 + R2 + 2
x304E0110001001000000x6240 LDR R1, R1, #0 ;R1 =
x304F0010101010010101x2A95 LD R5, x30E5 ;R5 = 0x18
x30501001001001111111x927F NOT R1, R1 ;R1 = ~R1 ;R1 = ~
x30510001001001100001x1261 ADD R1, R1, #1 ;R1 = ~ + 1
x30520001101101000001x1B41 ADD R5, R5, R1 ;R5 = 0x18 + (~ + 1) ;取非再加一的数学含义是取相反数,R5是用来标志循环是否结束的变量,初值0x18,终值为0.
x30530001111101100000x1F60 ADD R7, R5, #0 ;R7 = R5 = 0x18 + (~ + 1) ;考虑到的值为0x0~0x18,所以结果是0x18 - i,同时别忘了前面说过的字符串是倒序存储的
x30540000111000001100x0E0C BRNZPx3061
x30550001101101100000x1B60 ADD R5, R5, #0 ;if (R5 == 0) ????可能会影响标志位????
x30560000010000010101x0415 BRZ x306C ;GOTO SUCCESS
x30570001010010100011x14A3 ADD R2, R2, #3 ;R2 += 3
x30580000111110111000x0FB8 BRNZPx3011
x30590001000110000111x1187 ADD R0, R6, R7 ;R0 = + flag[]
x305A0000111111010101x0FD5 BRNZPx3030
x305B1001000110111111x91BF NOT R0, R6 ;R0 = ~R6 = ~FLAG[]
x305C0101000000000111x5007 AND R0, R0, R7 ;R0 = (~FLAG[]) & (FLAG[])
x305D1001001111111111x93FF NOT R1, R7 ;R1 = ~(FLAG[])
x305E0101001110000001x5381 AND R1, R6, R1 ;R1 = (FLAG[]) & (~(FLAG[]))
x305F0001000001000000x1040 ADD R0, R1, R0 ;R0 = ((FLAG[]) & (~(FLAG[]))) + ((~FLAG[]) & (FLAG[]))
x30600000111111100010x0FE2 BRNZPx3043
x30610010000010000010x2082 LD R0, x30E4 ;R0 = 0X4000
x30620001000000000110x1006 ADD R0, R0, R6 ;R0 = 0X4000 +
x30630110000000000000x6000 LDR R0, R0, #0 ;R0 = ] = FLAG[]
x30641110001010000001xE281 LEA R1, x30E6 ;R1 = 0x30E6 ;这里是LEA,不是LDR,我个老花眼看错了,怪不得下一条指令不太对劲。
x30650001001001000111x1247 ADD R1, R1, R7 ;R1 = 0x30E6 + 0x18 + (~ + 1)
x30660110001001000000x6240 LDR R1, R1, #0 ;R1 = + 1)]
x30671001001001111111x927F NOT R1, R1 ;R1 = ~ + 1)]
x30680001001001100001x1261 ADD R1, R1, #1 ;R1 = ~ + 1)] + 1 ;取 + 1)]的相反数
x30690001000000000001x1001 ADD R0, R0, R1 ;R0 = FLAG[] + (~ + 1)] + 1) = FLAG[] - + 1)],flag密文比较
x306A0000010111101010x05EA BRZ x3055 ;二者相等则继续
x306B0000111000000101x0E05 BRNZPx3071 ;不相等说明flag不对,GOTO try again
x306C0010000000001101x200D LD R0, x307A ;换行
x306D1111000000100001xF021 TRAP OUT
x306E1110000001000000xE040 LEA R0, x30AF ;SUCCESS!
x306F1111000000100010xF022 TRAP PUTS
x30700000111000000101x0E05 BRNZPx3076
x30710010000000001000x2008 LD R0, x307A ;换行
x30721111000000100001xF021 TRAP OUT
x30731110000001100101xE065 LEA R0, x30D9 ;TRY AGAIN!
x30741111000000100010xF022 TRAP PUTS
x30750000111000000000x0E00 BRNZPx3076
x30761111000000100101xF025 TRAP HALT
x30770000000000010001x0011 NOP
x30780000000000010011x0013 NOP
x30790000000000010100x0014 NOP
x307A0000000000001010x000A NOP
x307B0000000001010111x0057 NOP ;W
x307C0000000001100101x0065 NOP ;e
x307D0000000001101100x006C NOP ;l
x307E0000000001100011x0063 NOP ;c
x307F0000000001101111x006F NOP ;o
x30800000000001101101x006D NOP ;m
x30810000000001100101x0065 NOP ;e
x30820000000000100000x0020 NOP
x30830000000001110100x0074 NOP
x30840000000001101111x006F NOP
x30850000000000100000x0020 NOP
x30860000000001110100x0074 NOP
x30870000000001101000x0068 NOP
x30880000000001100101x0065 NOP
x30890000000000100000x0020 NOP
x308A0000000001110111x0077 NOP
x308B0000000001101111x006F NOP
x308C0000000001110010x0072 NOP
x308D0000000001101100x006C NOP
x308E0000000001100100x0064 NOP
x308F0000000000100000x0020 NOP
x30900000000001101111x006F NOP
x30910000000001100110x0066 NOP
x30920000000000100000x0020 NOP
x30930000000001001100x004C NOP
x30940000000001000011x0043 NOP
x30950000000000110011x0033 NOP
x30960000000000000000x0000 NOP
x30970000000001010000x0050 NOP
x30980000000001101100x006C NOP
x30990000000001100101x0065 NOP
x309A0000000001100001x0061 NOP
x309B0000000001110011x0073 NOP
x309C0000000001100101x0065 NOP
x309D0000000000100000x0020 NOP
x309E0000000001101001x0069 NOP
x309F0000000001101110x006E NOP
x30A00000000001110101x0075 NOP
x30A10000000001110000x0070 NOP
x30A20000000001110100x0074 NOP
x30A30000000000100000x0020 NOP
x30A40000000001111001x0079 NOP
x30A50000000001101111x006F NOP
x30A60000000001110101x0075 NOP
x30A70000000001110010x0072 NOP
x30A80000000000100000x0020 NOP
x30A90000000001100110x0066 NOP
x30AA0000000001101100x006C NOP
x30AB0000000001100001x0061 NOP
x30AC0000000001100111x0067 NOP
x30AD0000000000111010x003A NOP
x30AE0000000000000000x0000 NOP
x30AF0000000001010011x0053 NOP
x30B00000000001110101x0075 NOP
x30B10000000001100011x0063 NOP
x30B20000000001100011x0063 NOP
x30B30000000001100101x0065 NOP
x30B40000000001110011x0073 NOP
x30B50000000001110011x0073 NOP
x30B60000000000100001x0021 NOP
x30B70000000000100000x0020 NOP
x30B80000000001011001x0059 NOP
x30B90000000001101111x006F NOP
x30BA0000000001110101x0075 NOP
x30BB0000000001110010x0072 NOP
x30BC0000000000100000x0020 NOP
x30BD0000000001100110x0066 NOP
x30BE0000000001101100x006C NOP
x30BF0000000001100001x0061 NOP
x30C00000000001100111x0067 NOP
x30C10000000000100000x0020 NOP
x30C20000000001101001x0069 NOP
x30C30000000001110011x0073 NOP
x30C40000000000100000x0020 NOP
x30C50000000001111000x0078 NOP
x30C60000000001101101x006D NOP
x30C70000000001100011x0063 NOP
x30C80000000001110100x0074 NOP
x30C90000000001100110x0066 NOP
x30CA0000000001111011x007B NOP
x30CB0000000001111011x007B NOP
x30CC0000000001111001x0079 NOP
x30CD0000000001101111x006F NOP
x30CE0000000001110101x0075 NOP
x30CF0000000001110010x0072 NOP
x30D00000000000100000x0020 NOP
x30D10000000001101001x0069 NOP
x30D20000000001101110x006E NOP
x30D30000000001110000x0070 NOP
x30D40000000001110101x0075 NOP
x30D50000000001110100x0074 NOP
x30D60000000001111101x007D NOP
x30D70000000001111101x007D NOP
x30D80000000000000000x0000 NOP
x30D90000000001010100x0054 NOP
x30DA0000000001110010x0072 NOP
x30DB0000000001111001x0079 NOP
x30DC0000000000100000x0020 NOP
x30DD0000000001100001x0061 NOP ;a
x30DE0000000001100111x0067 NOP ;g
x30DF0000000001100001x0061 NOP ;a
x30E00000000001101001x0069 NOP ;i
x30E10000000001101110x006E NOP ;n
x30E20000000000100001x0021 NOP ;!
x30E30000000000000000x0000 NOP
x30E40100000000000000x4000 JSRR R0
x30E50000000000011000x0018 NOP
x30E60000000001101100x006C NOP
x30E70000000000001111x000F NOP
x30E80000000001010000x0050 NOP
x30E90000000001101100x006C NOP
x30EA0000000001101110x006E NOP
x30EB0000000001000010x0042 NOP
x30EC0000000000101100x002C NOP
x30ED0000000000101100x002C NOP
x30EE0000000000011110x001E NOP
x30EF0000000000001100x000C NOP
x30F00000000000001101x000D NOP
x30F10000000000000000x0000 NOP
x30F20000000000110011x0033 NOP
x30F30000000000111101x003D NOP
x30F40000000000010111x0017 NOP
x30F50000000000000001x0001 NOP
x30F60000000000101011x002B NOP
x30F70000000000111100x003C NOP
x30F80000000000001100x000C NOP
x30F90000000000000010x0002 NOP
x30FA0000000000011101x001D NOP
x30FB0000000000011100x001C NOP
x30FC0000000000001001x0009 NOP
x30FD0000000000010001x0011 NOP
x30FE0000000000010001x0011 NOP
x30FF0000000000010011x0013 NOP
x31000000000000000001x0001 NOP
x31010000000000000000x0000 NOP
x31020000000000010100x0014 NOP
x31030000000000000000x0000 NOP
x31040000000000000000x0000 NOP
x31050000000000010011x0013 NOP
x31060000000000000010x0002 NOP
x31070000000000000001x0001 NOP
x31080000000000010100x0014 NOP
x31090000000000000001x0001 NOP
x310A0000000000000001x0001 NOP
x310B0000000000010011x0013 NOP
x310C0000000000000011x0003 NOP
x310D0000000000000010x0002 NOP
x310E0000000000010100x0014 NOP
x310F0000000000000010x0002 NOP
x31100000000000000010x0002 NOP
x31110000000000010011x0013 NOP
x31120000000000000100x0004 NOP
x31130000000000000011x0003 NOP
x31140000000000010100x0014 NOP
x31150000000000000011x0003 NOP
x31160000000000000011x0003 NOP
x31170000000000010011x0013 NOP
x31180000000000000101x0005 NOP
x31190000000000000100x0004 NOP
x311A0000000000010100x0014 NOP
x311B0000000000000100x0004 NOP
x311C0000000000000100x0004 NOP
x311D0000000000010011x0013 NOP
x311E0000000000000110x0006 NOP
x311F0000000000000101x0005 NOP
x31200000000000010100x0014 NOP
x31210000000000000101x0005 NOP
x31220000000000000101x0005 NOP
x31230000000000010011x0013 NOP
x31240000000000000111x0007 NOP
x31250000000000000110x0006 NOP
x31260000000000010100x0014 NOP
x31270000000000000110x0006 NOP
x31280000000000000110x0006 NOP
x31290000000000010011x0013 NOP
x312A0000000000001000x0008 NOP
x312B0000000000000111x0007 NOP
x312C0000000000010100x0014 NOP
x312D0000000000000111x0007 NOP
x312E0000000000000111x0007 NOP
x312F0000000000010011x0013 NOP
x31300000000000001001x0009 NOP
x31310000000000001000x0008 NOP
x31320000000000010100x0014 NOP
x31330000000000001000x0008 NOP
x31340000000000001000x0008 NOP
x31350000000000010011x0013 NOP
x31360000000000001010x000A NOP
x31370000000000001001x0009 NOP
x31380000000000010100x0014 NOP
x31390000000000001001x0009 NOP
x313A0000000000001001x0009 NOP
x313B0000000000010011x0013 NOP
x313C0000000000001011x000B NOP
x313D0000000000001010x000A NOP
x313E0000000000010100x0014 NOP
x313F0000000000001010x000A NOP
x31400000000000001010x000A NOP
x31410000000000010011x0013 NOP
x31420000000000001100x000C NOP
x31430000000000001011x000B NOP
x31440000000000010100x0014 NOP
x31450000000000001011x000B NOP
x31460000000000001011x000B NOP
x31470000000000010011x0013 NOP
x31480000000000001101x000D NOP
x31490000000000001100x000C NOP
x314A0000000000010100x0014 NOP
x314B0000000000001100x000C NOP
x314C0000000000001100x000C NOP
x314D0000000000010011x0013 NOP
x314E0000000000001110x000E NOP
x314F0000000000001101x000D NOP
x31500000000000010100x0014 NOP
x31510000000000001101x000D NOP
x31520000000000001101x000D NOP
x31530000000000010011x0013 NOP
x31540000000000001111x000F NOP
x31550000000000001110x000E NOP
x31560000000000010100x0014 NOP
x31570000000000001110x000E NOP
x31580000000000001110x000E NOP
x31590000000000010011x0013 NOP
x315A0000000000010000x0010 NOP
x315B0000000000001111x000F NOP
x315C0000000000010100x0014 NOP
x315D0000000000001111x000F NOP
x315E0000000000001111x000F NOP
x315F0000000000010011x0013 NOP
x31600000000000010001x0011 NOP
x31610000000000010000x0010 NOP
x31620000000000010100x0014 NOP
x31630000000000010000x0010 NOP
x31640000000000010000x0010 NOP
x31650000000000010011x0013 NOP
x31660000000000010010x0012 NOP
x31670000000000010001x0011 NOP
x31680000000000010100x0014 NOP
x31690000000000010001x0011 NOP
x316A0000000000010001x0011 NOP
x316B0000000000010011x0013 NOP
x316C0000000000010011x0013 NOP
x316D0000000000010010x0012 NOP
x316E0000000000010100x0014 NOP
x316F0000000000010010x0012 NOP
x31700000000000010010x0012 NOP
x31710000000000010011x0013 NOP
x31720000000000010100x0014 NOP
x31730000000000010011x0013 NOP
x31740000000000010100x0014 NOP
x31750000000000010011x0013 NOP
x31760000000000010011x0013 NOP
x31770000000000010011x0013 NOP
x31780000000000010101x0015 NOP
x31790000000000010100x0014 NOP
x317A0000000000010100x0014 NOP
x317B0000000000010100x0014 NOP
x317C0000000000010100x0014 NOP
x317D0000000000010011x0013 NOP
x317E0000000000010110x0016 NOP
x317F0000000000010101x0015 NOP
x31800000000000010100x0014 NOP
x31810000000000010101x0015 NOP
x31820000000000010101x0015 NOP
x31830000000000010011x0013 NOP
x31840000000000010111x0017 NOP
x31850000000000010110x0016 NOP
x31860000000000010100x0014 NOP
x31870000000000010110x0016 NOP
x31880000000000010110x0016 NOP
x31890000000000010011x0013 NOP
x318A0000000000011000x0018 NOP
x318B0000000000010111x0017 NOP
x318C0000000000010100x0014 NOP
x318D0000000000010111x0017 NOP
x318E0000000000010111x0017 NOP
x318F0000000000010100x0014 NOP
x31900000000000011000x0018 NOP
x31910000000000011000x0018 NOP
x31920000000000000000x0000 NOP
x31930000000000000000x0000 NOP
x31940000000000000000x0000 NOP
x31950000000000000000x0000 NOP
x31960000000000000000x0000 NOP
x31970000000000000000x0000 NOP
x31980000000000000000x0000 NOP
x31990000000000000000x0000 NOP
x319A0000000000000000x0000 NOP
x319B0000000000000000x0000 NOP
x319C0000000000000000x0000 NOP
x319D0000000000000000x0000 NOP
x319E0000000000000000x0000 NOP
x319F0000000000000000x0000 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 = b + flag
* 0x13的case,对应0x3035的代码,flag = (flag & ~(flag)) + ((~flag) & flag)
* 0x14的case,对应0x3048的代码,验证flag == cipher
需要注意一点,有意思的是~n + 1表示的是n的相反数,所以m + (~n + 1)表示的是m-n,利用结果是否等于0,可以选择是否进行跳转(BRZ)
回到主要的逻辑上来,结合上面的0x30FF的数据,你会发现其实是类似这样的:
```python
#a,b,c是0x30FF的第i组
for i in range(24):
flag = (flag & ~(flag)) + ((~flag) & flag)
if flag != cipher:
exit()
if flag != cipher:
exit()
print('正确')
```
那行等式我没想出怎么逆,好像也逆不了??所以直接爆破了。可以写出下面的脚本:
> 几个小时后的补充:
>
> 看了看队友的博客,他的脚本居然只有异或??
>
> 试了下,发现`(~a & b) + (a & ~b) = a ^ b`,哇,居然还有这种化简。
>
> 其实仔细想想,确实是这样的。
>
> 因为a和~a的存在,导致针对具体的某一bit,(~a & b)和(a & ~b)二者必不可能同时为1,所以加法进位的问题不复存在。
>
> 不过脚本我就不改啦,你们自己写的时候就不用爆破了,直接用异或解就行。
```python
code = '''x30E40100000000000000x4000 JSRR R0
x30E50000000000011000x0018 NOP
x30E60000000001101100x006C NOP
x30E70000000000001111x000F NOP
x30E80000000001010000x0050 NOP
x30E90000000001101100x006C NOP
x30EA0000000001101110x006E NOP
x30EB0000000001000010x0042 NOP
x30EC0000000000101100x002C NOP
x30ED0000000000101100x002C NOP
x30EE0000000000011110x001E NOP
x30EF0000000000001100x000C NOP
x30F00000000000001101x000D NOP
x30F10000000000000000x0000 NOP
x30F20000000000110011x0033 NOP
x30F30000000000111101x003D NOP
x30F40000000000010111x0017 NOP
x30F50000000000000001x0001 NOP
x30F60000000000101011x002B NOP
x30F70000000000111100x003C NOP
x30F80000000000001100x000C NOP
x30F90000000000000010x0002 NOP
x30FA0000000000011101x001D NOP
x30FB0000000000011100x001C NOP
x30FC0000000000001001x0009 NOP
x30FD0000000000010001x0011 NOP
x30FE0000000000010001x0011 NOP
x30FF0000000000010011x0013 NOP
x31000000000000000001x0001 NOP
x31010000000000000000x0000 NOP
x31020000000000010100x0014 NOP
x31030000000000000000x0000 NOP
x31040000000000000000x0000 NOP
x31050000000000010011x0013 NOP
x31060000000000000010x0002 NOP
x31070000000000000001x0001 NOP
x31080000000000010100x0014 NOP
x31090000000000000001x0001 NOP
x310A0000000000000001x0001 NOP
x310B0000000000010011x0013 NOP
x310C0000000000000011x0003 NOP
x310D0000000000000010x0002 NOP
x310E0000000000010100x0014 NOP
x310F0000000000000010x0002 NOP
x31100000000000000010x0002 NOP
x31110000000000010011x0013 NOP
x31120000000000000100x0004 NOP
x31130000000000000011x0003 NOP
x31140000000000010100x0014 NOP
x31150000000000000011x0003 NOP
x31160000000000000011x0003 NOP
x31170000000000010011x0013 NOP
x31180000000000000101x0005 NOP
x31190000000000000100x0004 NOP
x311A0000000000010100x0014 NOP
x311B0000000000000100x0004 NOP
x311C0000000000000100x0004 NOP
x311D0000000000010011x0013 NOP
x311E0000000000000110x0006 NOP
x311F0000000000000101x0005 NOP
x31200000000000010100x0014 NOP
x31210000000000000101x0005 NOP
x31220000000000000101x0005 NOP
x31230000000000010011x0013 NOP
x31240000000000000111x0007 NOP
x31250000000000000110x0006 NOP
x31260000000000010100x0014 NOP
x31270000000000000110x0006 NOP
x31280000000000000110x0006 NOP
x31290000000000010011x0013 NOP
x312A0000000000001000x0008 NOP
x312B0000000000000111x0007 NOP
x312C0000000000010100x0014 NOP
x312D0000000000000111x0007 NOP
x312E0000000000000111x0007 NOP
x312F0000000000010011x0013 NOP
x31300000000000001001x0009 NOP
x31310000000000001000x0008 NOP
x31320000000000010100x0014 NOP
x31330000000000001000x0008 NOP
x31340000000000001000x0008 NOP
x31350000000000010011x0013 NOP
x31360000000000001010x000A NOP
x31370000000000001001x0009 NOP
x31380000000000010100x0014 NOP
x31390000000000001001x0009 NOP
x313A0000000000001001x0009 NOP
x313B0000000000010011x0013 NOP
x313C0000000000001011x000B NOP
x313D0000000000001010x000A NOP
x313E0000000000010100x0014 NOP
x313F0000000000001010x000A NOP
x31400000000000001010x000A NOP
x31410000000000010011x0013 NOP
x31420000000000001100x000C NOP
x31430000000000001011x000B NOP
x31440000000000010100x0014 NOP
x31450000000000001011x000B NOP
x31460000000000001011x000B NOP
x31470000000000010011x0013 NOP
x31480000000000001101x000D NOP
x31490000000000001100x000C NOP
x314A0000000000010100x0014 NOP
x314B0000000000001100x000C NOP
x314C0000000000001100x000C NOP
x314D0000000000010011x0013 NOP
x314E0000000000001110x000E NOP
x314F0000000000001101x000D NOP
x31500000000000010100x0014 NOP
x31510000000000001101x000D NOP
x31520000000000001101x000D NOP
x31530000000000010011x0013 NOP
x31540000000000001111x000F NOP
x31550000000000001110x000E NOP
x31560000000000010100x0014 NOP
x31570000000000001110x000E NOP
x31580000000000001110x000E NOP
x31590000000000010011x0013 NOP
x315A0000000000010000x0010 NOP
x315B0000000000001111x000F NOP
x315C0000000000010100x0014 NOP
x315D0000000000001111x000F NOP
x315E0000000000001111x000F NOP
x315F0000000000010011x0013 NOP
x31600000000000010001x0011 NOP
x31610000000000010000x0010 NOP
x31620000000000010100x0014 NOP
x31630000000000010000x0010 NOP
x31640000000000010000x0010 NOP
x31650000000000010011x0013 NOP
x31660000000000010010x0012 NOP
x31670000000000010001x0011 NOP
x31680000000000010100x0014 NOP
x31690000000000010001x0011 NOP
x316A0000000000010001x0011 NOP
x316B0000000000010011x0013 NOP
x316C0000000000010011x0013 NOP
x316D0000000000010010x0012 NOP
x316E0000000000010100x0014 NOP
x316F0000000000010010x0012 NOP
x31700000000000010010x0012 NOP
x31710000000000010011x0013 NOP
x31720000000000010100x0014 NOP
x31730000000000010011x0013 NOP
x31740000000000010100x0014 NOP
x31750000000000010011x0013 NOP
x31760000000000010011x0013 NOP
x31770000000000010011x0013 NOP
x31780000000000010101x0015 NOP
x31790000000000010100x0014 NOP
x317A0000000000010100x0014 NOP
x317B0000000000010100x0014 NOP
x317C0000000000010100x0014 NOP
x317D0000000000010011x0013 NOP
x317E0000000000010110x0016 NOP
x317F0000000000010101x0015 NOP
x31800000000000010100x0014 NOP
x31810000000000010101x0015 NOP
x31820000000000010101x0015 NOP
x31830000000000010011x0013 NOP
x31840000000000010111x0017 NOP
x31850000000000010110x0016 NOP
x31860000000000010100x0014 NOP
x31870000000000010110x0016 NOP
x31880000000000010110x0016 NOP
x31890000000000010011x0013 NOP
x318A0000000000011000x0018 NOP
x318B0000000000010111x0017 NOP
x318C0000000000010100x0014 NOP
x318D0000000000010111x0017 NOP
x318E0000000000010111x0017 NOP
x318F0000000000010100x0014 NOP
x31900000000000011000x0018 NOP
x31910000000000011000x0018 NOP '''
import re
lines = code.split('\n')
data = []
for line in lines:
r = re.search(r'x{4} *?\d{16} *?x{2}({2})', line)
data.append(int(r.group(1), 16))
cipher = data
'''
op = data
for i in range(len(op)//3):
t = op
a, b, c = t, t, t
#print(hex(a), b, c)
'''
flag = * 25
flag = cipher
for i in range(23, -1, -1):
for j in range(32, 127):
if cipher == (flag & (~j)) + ((~flag) & j):
flag = 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)`显示镜像详情。
```
# 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 Revert "remove file"
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 wwwroot/.flag.html.swp
```
拿到`.flag.html.swp`,打开后在末尾发现flag。
参考:
* (https://www.cnblogs.com/zejin2008/p/13460498.html)
* 随便一篇git历史回滚的文章
### capture
提取坐标:
```python
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}`
参考:(https://blog.csdn.net/lwb102063/article/details/50782696)
### 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的文末
参考:
* [官网](http://www.whence.com/minimodem/)
* [类似的题1](https://ctftime.org/writeup/8689)
* [类似的题2](https://tuanlinh.gitbook.io/ctf/matesctf-2018-round-3) 小朋友呢 发表于 2020-9-1 22:44
师傅tql,师傅是如何分析这个easy_re这个是VM的,解这个VM需要了解什么相关的基础
1、我也是菜鸡一个。
2、看到读取操作码这一行为,可以判断出这是VM.
3、也不需要啥基础吧,多看几道VM,就慢慢了解了。我也是刚接触VM没多久。 小朋友呢 发表于 2020-9-2 10:46
师傅有推荐逆vm这种题练手的这种网站吗
没有专门的网站,不过网上有很多vm的题解,跟着做做也行。
我是看令则大佬的这篇博客入的vm的门:https://bbs.pediy.com/thread-259116.htm 同样是markdown,为啥这里就看不到图片了?这还能跨域不成?
文章同时发在我的博客http://blog.iyzyi.com/index.php/archives/1625/ iyzyi 发表于 2020-9-1 13:36
同样是markdown,为啥这里就看不到图片了?这还能跨域不成?
文章同时发在我的博客http://blog.iyzyi.com/ ...
https禁止加载http的请求了吧,直接上传本地吧。 师傅tql,师傅是如何分析这个easy_re这个是VM的,解这个VM需要了解什么相关的基础 大佬太强了{:1_893:} iyzyi 发表于 2020-9-2 01:07
1、我也是菜鸡一个。
2、看到读取操作码这一行为,可以判断出这是VM.
3、也不需要啥基础吧,多看几道VM ...
师傅有推荐逆vm这种题练手的这种网站吗 厉害了,大佬 大佬太强了