2021美团安洵暗泉re部分复现
typora-copy-images-to: ./
安洵杯
sign_in
贪吃蛇 虽然没啥用 smc解密拿一下flag相关的部分
倒着看看sub_40105F 和sub_401055函数
写出解密算法后发现v5不太对 所以爆破一下v5 反回去看到v5是byte赋值来的
#include
#include
#include
#include
using namespace std;
#include
#include
#include
unsigned char Enc[] = { 0xA5, 0xD8, 0x8E, 0xBF, 0xF9, 0xA9, 0x15, 0xE1, 0x8A,
0xF0,
0xD3, 0xFC, 0x46, 0x89, 0xBF, 0x8B, 0x62, 0xB1, 0x08, 0xC3,
0x29, 0xCF, 0x19, 0x2B, 0x56, 0x06, 0x77, 0x7A, 0xBA, 0xE4,
0xBA, 0xA4, 0xE4, 0x8C, 0x3E, 0x4E, 0xD9, 0xE1, 0xA7, 0x01,
0x04, 0xCE, 0xE9, 0x75, 0xB9, 0x93, 0xB5, 0x22, 0xB4, 0x42,
0x77, 0x49, 0xF6, 0x15, 0xEB, 0x24, 0x0E, 0xFF, 0xC2, 0xF2,
0x39, 0x30, 0x97, 0x47, 0x0D, 0xCA, 0x01, 0xC8, 0x61, 0x58,
0x12, 0x6A, 0xE8, 0x0B, 0x32, 0x80, 0x47, 0xBD, 0x85, 0x03,
0xDD, 0x6D, 0xF9, 0x69, 0xD1, 0x90, 0x64, 0xE5, 0x4B, 0xAD,
0x3C, 0x2D, 0xBE, 0x00, 0x42, 0x2D, 0x79, 0x69, 0xEF, 0x89,
0x5D, 0x88, 0x91, 0x4A, 0xC7, 0xEB, 0x9D, 0x01, 0x96, 0xFD,
0xF8, 0x3B, 0x57, 0x25, 0xDD, 0x1B, 0xDD, 0x5F, 0x68, 0xB8,
0x14, 0x66, 0x22, 0x57, 0x28, 0x5C, 0x58, 0x9F };
DWORD a2[] = { 68,48,103,51 };
DWORD key[] = { 68,48,103,51 };
DWORD get_v8(int times, int x) {
DWORD v5 = 'D3g0' + x;
DWORD v8 = 0;
for (int i = 0; i < times; i++) {
v8 += v5;
}
return v8;
}
void my_TEAdecode() {
uint32_t a1[32] = { 0 };
for (int x = 0; x < 256; x++) {
x = 77;
memcpy(a1, Enc, 128);
for (int v7 = 7; v7 > 0; v7--) {
DWORD v8 = get_v8(v7, x);
DWORD v6 = (v8 >> 2) & 3;
DWORD v9 = a1[30];
a1[31] -= ((v9 ^ (a2[v6 ^ 31 & 3])) + (*a1 ^ v8)) ^ (((16 * v9)
^ (*a1 >> 3))
+ ((4 * *a1) ^ (v9 >> 5)));
for (int i = 30; i >= 0; i--) {
if (i == 0) {
v9 = a1[31];
a1[i] -= ((v9 ^ a2[v6 ^ i & 3]) + (a1[i + 1] ^ v8)) ^ (((16 * v9) ^ (a1[i + 1] >> 3))
+ ((4 * a1[i + 1]) ^ (v9 >> 5)));
}
else {
v9 = a1[i - 1];
a1[i] -= ((v9 ^ a2[v6 ^ i & 3]) + (a1[i + 1] ^ v8)) ^ (((16 * v9) ^ (a1[i + 1] >> 3))
+ ((4 * a1[i + 1]) ^ (v9 >> 5)));
}
}
}
//bytes 赋值来的 所以肯定小于256
if (a1[0] < 256) {
printf("%d,%d\n", x, a1[0]);
break;
}
}
for (int i = 0; i < 32; i++) {
printf("%d,", a1[i]);
}
}
int main() {
my_TEAdecode();
//解得ENC为
char ENC[] = { 60,64,43,102,111,79,92,29,66,26,43,87,54,68,51,28,29,107,92,6,15,28,92,26,43,9,50,110,21,90,44,37, };
}
然后一步步解密即可
# tea解密出来得
enc = [60, 64, 43, 102, 111, 79, 92, 29, 66, 26, 43, 87, 54, 68, 51, 28, 29, 107, 92, 6, 15, 28, 92, 26, 43, 9, 50, 110,
21, 90, 44, 37]
know = [0xA5, 0xD8, 0x8E, 0xBF, 0xF9, 0xA9, 0x15, 0xE1, 0x8A, 0xF0,
0xD3, 0xFC, 0x46, 0x89, 0xBF, 0x8B, 0x62, 0xB1, 0x08, 0xC3,
0x29, 0xCF, 0x19, 0x2B, 0x56, 0x06, 0x77, 0x7A, 0xBA, 0xE4,
0xBA, 0xA4, 0xE4, 0x8C, 0x3E, 0x4E, 0xD9, 0xE1, 0xA7, 0x01,
0x04, 0xCE, 0xE9, 0x75, 0xB9, 0x93, 0xB5, 0x22, 0xB4, 0x42,
0x77, 0x49, 0xF6, 0x15, 0xEB, 0x24, 0x0E, 0xFF, 0xC2, 0xF2,
0x39, 0x30, 0x97, 0x47, 0x0D, 0xCA, 0x01, 0xC8, 0x61, 0x58,
0x12, 0x6A, 0xE8, 0x0B, 0x32, 0x80, 0x47, 0xBD, 0x85, 0x03,
0xDD, 0x6D, 0xF9, 0x69, 0xD1, 0x90, 0x64, 0xE5, 0x4B, 0xAD,
0x3C, 0x2D, 0xBE, 0x00, 0x42, 0x2D, 0x79, 0x69, 0xEF, 0x89,
0x5D, 0x88, 0x91, 0x4A, 0xC7, 0xEB, 0x9D, 0x01, 0x96, 0xFD,
0xF8, 0x3B, 0x57, 0x25, 0xDD, 0x1B, 0xDD, 0x5F, 0x68, 0xB8,
0x14, 0x66, 0x22, 0x57, 0x28, 0x5C, 0x58, 0x9F]
kk = []
v1 = [0] * 300
j = 0
i = 0
v7 = 0
table = [0] * 32
#原先函数的逻辑就是将输入值打乱 所以现在看看打乱顺序是什么
v6 = [x for x in range(1, 33)]
while (i < 32):
if (j % 6 >= 3):
v1[32 * (3 - j % 3) + i] = v6[i]
else:
v1[32 * (j % 3) + i] = v6[i]
i += 1
j += 1
for i in range(4):
for j in range(32):
if (v1[32 * i + j]):
table[v7] = v1[32 * i + j]
v7 += 1
for index in range(len(enc)):
table[index] -= 1
sb = [0] * 32
for index in range(32):
sb[table[index]] = enc[index]
sb[31] ^= sb[0]
for i in range(31, 0, -1):
sb[i - 1] ^= sb[i % 32]
sb = "".join(list(map(chr, sb)))
print(sb)
maze
并没有算出迷宫解法 这个迷宫怎么走也走不对 所以抄了别人的迷宫答案复现下面的部分
base64换表密码很简单 上脚本什么的都行 解出来一半flag
最后的异或逻辑什么的也能看懂 虽然我并不知道为什么要异或...
DNUICTF
sign_in
打开就是flag
happyctf
拿到字符串梭了 不想看逻辑
a="rxusoCqxw{yqK`{KZqag{r`i"
b=list(map(ord,list(a)))
print(b)
for i in range(100):
print()
for index in range(len(a)):
print(chr(ord(a[index])^i),end="")
rc4
x = [0xE8, 0x9B, 0x41, 0x28, 0xCC, 0x7F, 0xDF, 0x20, 0x2C, 0x54,
0x6E, 0x5F, 0xBE, 0x0E, 0xA4, 0x7B, 0xCF, 0x46, 0xED, 0x71,
0xE8, 0x46, 0x7E, 0x7D, 0x00, 0xA3, 0x0B, 0x40]
p = []
# 穿了一堆2进去 然后动调拿到x
for c in x:
p.append(c ^ ord("2"))
print(p)
enc = [0x9E, 0xE7, 0x30, 0x5F, 0xA7, 0x01, 0xA6, 0x53, 0x59, 0x1B,
0x0A, 0x20, 0xF1, 0x73, 0xD1, 0x0E, 0xAB, 0x09, 0x84, 0x0E,
0x8D, 0x2B, ]
ENC = []
for x in enc:
ENC.append(x ^ 0x22)
print(ENC)
# p现在是密钥
for index in range(len(ENC)):
print(chr(p[index] ^ ENC[index]), end="")
easyre
直到现在我也没动态调出来 但是gdb操作学了一堆...
然后看了加密与解密的二十章二十一章
现在勉强能看懂别的师傅的注册机写法
https://mp.weixin.qq.com/s/KgxHOFH52EE8z7NnMTSIDA 别的师傅的wp
本题是通过用linux的信号来触发各个函数 相当于写了个虚拟机 所以我们有两种思路 一是分析一下每个函数的作用 二是动态调试直接看结果是怎么变化的
先拿到他都发送了什么信号
[17, 52, 0, 42, 5, 16, 20, 9, 23, 0, 36, 5, 3, 17, 29, 6, 0, 0, 5, 3, 17, 64, 6, 0, 72, 5, 17, 29, 23, 14, 1, 21, 4, 15, 1, 22, 2, 0, 0, 4, 3, 5, 16, 20, 50, 5, 9, 2, 19, 29, 5, 18, 21, 4, 16, 20, 61, 10, 1, 19, 52, 3, 4, 18, 14, 1, 21, 4, 7, 1, 22, 2, 0, 0, 4, 3, 5, 16, 20, 85, 5, 9, 1, 19, 64, 5, 18]
在init里面有一堆信号处理函数 一个个分析对应 理解一下都是干什么的....
抄了一份脚本慢慢分析
opcode=[17, 52, 0, 42, 5, 16, 20, 9, 23, 0, 36, 5, 3, 17, 29, 6, 0, 0, 5, 3, 17, 64, 6, 0, 72, 5, 17, 29, 23, 14, 1, 21, 4, 15, 1, 22, 2, 0, 0, 4, 3, 5, 16, 20, 50, 5, 9, 2, 19, 29, 5, 18, 21, 4, 16, 20, 61, 10, 1, 19, 52, 3, 4, 18, 14, 1, 21, 4, 7, 1, 22, 2, 0, 0, 4, 3, 5, 16, 20, 85, 5, 9, 1, 19, 64, 5, 18]
data=[0]*512
cnt=0
target=0
def sig_hand(sig:int,a1=None):
global cnt
s='unknown:{}'.format(sig)
if sig==34:
# data[esp++]=a1
s='push {}'.format(a1)
elif sig==35:
s='pop {}'.format(a1)
elif sig==36:
s='add rax,rbx'
elif sig==37:
s='add {},{}'.format(a1,target)
elif sig==38:
s='sub rax,rbx'
elif sig==39:
s='sub {},{}'.format(a1,target)
elif sig==40:
s='xor rax,rbx'
elif sig==41:
s='test rax,rbx' # set flag
elif sig==42:
s='call {}'.format(target)
elif sig==43:
s='ret'
elif sig==44:
s='jmp {}'.format(target)
elif sig==45:
s='jz {}'.format(target)
elif sig==46:
s='push data[rcx]'
elif sig==47:
s='pop data[rcx]'
elif sig==2:
s='check'
return s
ip_lst=[0,8,9,10,12,13,14,17,19,20]
while cnt
拿到汇编结果后就很简单了 就是简单的异或和加减运算 直接写解密脚本
enc = [0xA3, 0xD8, 0xAC, 0xA9, 0xA8, 0xD6, 0xA6, 0xCD, 0xD0, 0xD5,
0xF7, 0xB7, 0x9C, 0xB3, 0x31, 0x2D, 0x40, 0x5B, 0x4B, 0x3A,
0xFD, 0x57, 0x42, 0x5F, 0x58, 0x52, 0x54, 0x1B, 0x0C, 0x78,
0x39, 0x2D, 0xD9, 0x3D, 0x35, 0x1F, 0x09, 0x41, 0x40, 0x47,
0x42, 0x11]
p = []
for index in range(len(enc)):
p.append(((enc[index] ^ (0x9a - index * 2)) - 41 + index) ^ (0x76 - index * 2))
for x in p:
print(chr(x), end="")
美团
random
多输入几个值会发现 这个random其实是定值 直接传一串a进去 动态拿到异或后结果
a = [ 0x39, 0xC0, 0xAA, 0x88, 0x8C, 0x4D, 0x8D, 0x9A, 0x88, 0xA5,
0x77, 0xF6, 0xF8, 0xD0, 0xC5, 0x88, 0xA2, 0xA7, 0xE1, 0xDE,
0x5F, 0x25, 0x79, 0x4F, 0x12, 0x37, 0x33, 0xD9, 0x3A, 0x07,
0x8C, 0xDD, 0xEB, 0xB9, 0x57, 0xEE, 0x87, 0xB2, 0xD0, 0x30,
0xD8, 0x38]
b = [0x3E, 0xCD, 0xAA, 0x8E, 0x96, 0x1F, 0x89, 0xCD, 0xDB, 0xF1,
0x70, 0xF2, 0xA9, 0x9C, 0xC2, 0x8B, 0xF2, 0xFE, 0xAD, 0x8B,
0x58, 0x7C, 0x2F, 0x03, 0x4A, 0x65, 0x31, 0x89, 0x76, 0x57,
0x88, 0xDF, 0xB8, 0xE9, 0x01, 0xE9a, 0xDE, 0xE5, 0x86, 0x68,
0x8F, 0x24, 0xD3, 0x5A]
print('a'*42)
print(chr(0x61))
for index in range(len(a)):
print(chr(a[index] ^ 0x61 ^ b[index]), end="")
wow
萌新大受震撼 是32位程序运行64位代码
https://zhuanlan.zhihu.com/p/57648345
根据文章内容
在x64系统下的进程是有32位和64位两种工作模式,这两种工作模式的区别在于CS寄存器。32位模式时,CS = 0x23;64位模式时,CS = 0x33。;
这两种工作模式是可以进行切换的,一般会通过retf指令,一条retf指令等效于以下2条汇编指令
pop ip
pop cs
如果此时栈中有0x33,则会将0x33弹出到CS寄存器中,实现32位程序切换到64位代码的过程。所以retf是识别32位程序调用64位代码的重要标志。
很明显的切换标志 所以我们把下面的代码dump出来 用ida64位重新分析
xxtea 但是改了一下delta和rounds 网上随便找个脚本即可