reverse1
两个rc4加密,一个是原版另一个是被修改的版本。加密过程就是用key1先加密key,再用加密的key去加密flag。所以按照这个逻辑来逆向即可解密。rc4原版加密是对称加密,而修改版的rc4只要把减号改为加号就行。
在比赛时这题并没有写出来,脚本最后的结果一直是乱码,后面复盘时发现了一个关键的东西。当盒子是char类型时,只要盒子里的元素被当作下标时,就要把这个下标转成(unsigned char),如果不转的话在后面的下标就是一个负数。当盒子是unsigned char类型时,(box[v5] + box[v6])作为下标时要转化为(unsigned char),如果不转化的话(box[v5] + box[v6])就有可能会超过下标255。所以box[(unsigned char)(box[v5] + box[v6])]实际上就是box[(box[v5] + box[v6])%256]。
- 所以在写题中一定要注意下标的数值是否合规。
#include <stdio.h>
#include <string.h>
char input[32] = {
0x4E, 0x47, 0x38, 0x47, 0x62, 0x0A, 0x79, 0x6A, 0x03, 0x66, 0xC0, 0x69, 0x8D, 0x1C, 0x84, 0x0F,
0x54, 0x4A, 0x3B, 0x08, 0xE3, 0x30, 0x4F, 0xB9, 0x6C, 0xAB, 0x36, 0x24, 0x52, 0x81, 0xCF, 0x00
};
char key[100] = "ban_debug!";
char key1[] = "keykey";
unsigned char box[256];
int getbox(unsigned char*box, char*key,int keylen) {
char v4;
int v6 = 0;
int v8[256];
memset(v8, 0, 0x400uLL);
for (int i = 0; i <= 255; ++i)
{
box[i] = i;
v8[i] = (unsigned char)key[i % keylen];
}
v6 = 0;
for (int j = 0; j <= 255; ++j)
{
v6 = (v8[j] + v6 + box[j]) % 256;
v4 = box[j];
box[j] = box[v6];
box[v6] = v4;
}
return 0;
}
int dec1(unsigned char*box, unsigned char* input,int len) {
char v4;
int v5;
int v6;
int i;
v5 = 0;
v6 = 0;
for (i = 0; ; ++i)
{
if (len <= i)
break;
v5 = (v5 + 1) % 256;
v6 = (v6 + box[v5]) % 256;
v4 = box[v5];
box[v5] = box[v6];
box[v6] = v4;
input[i] ^= box[(unsigned char)(box[v5] + box[v6])];
}
return 0;
}
int dec2(unsigned char* box,char* input, int len) {
char v4;
int v5;
int v6;
int i;
v5 = 0;
v6 = 0;
for (i = 0; ; ++i)
{
if (len <= i)
break;
v5 = (v5 + 1) % 256;
v6 = (v6 + box[v5]) % 256;
v4 = box[v5];
box[v5] = box[v6];
box[v6] = v4;
input[i] += box[(unsigned char)(box[v5] + box[v6])];
}
return 0;
}
int main() {
getbox(box, key1, strlen(key1));
dec1(box, (unsigned char*)key, strlen(key));
memset(box, 0, sizeof(box));
getbox(box, key, strlen(key));
dec2(box, input, 32);
for (int i = 0; i < 31; i++) {
printf("%c", input[i]);
}
//puts(input);
}
reverse2
用010editer把ABC全部修改为UPX,ida分析后就是一个base64加密函数,直接就可以看到明文和码表,直接解密就得flag