1.findme:
用die查一下可以看到是64位的程序,使用64位的ida打开:
可以看到给出了两个像是flag的东西,事实上全都是错的 ,那么我们的关注点就在Buffer上面了:
这里出现了MZ 90,那么就猜测是exe文件头,转化为数组之后导出数组(shift + E)
可以看到像4D5A之间有很多个零,所以我们就得把之间多于的零去掉,使用脚本处理:
首先在shift + E的窗口下面的output file改写为ral,然后再在这一个窗口打开ida脚本编写的地方:
(File ->script command...)
编写脚本:
f = open("ral", "rb").read()
arr = [f[i] for i in range(0, len(f), 4)]
open("dump.exe", "wb").write(bytes(arr))
print("done!")
f = open("ral", "rb").read():这一个代码的作用是打开一个名为“ral”的文件(就是之前我们设置名字的那个,)以二进制模式(“rb”)读取文件的内容,并将内容存储在变量 f
中
arr = [f[i] for i in range(0, len(f), 4)]:这一行代码的作用是创建一个表arr,其中每一个元素使变量 f 中的数据,从零开始,每隔4给位置取一个元素
open("dump.exe","wb").write(bytes(arr)):这一行代码的作用是以二进制写入模式(“wb”)打开一个名为 “dump.exe” 的文件,然后将列表 arr
中的数据转换为字节类型,并写入到 “dump.exe” 文件中。实际上,这行代码将提取的数据写入到一个新的二进制文件 “dump.exe” 中。
print("done!"):这一行代码就是输出消息代表执行完毕
还可以使用另外一个方法,使用vs2022写一个脚本来执行:
#include <stdio.h>
#include <stdlib.h>
#include<iostream>
#include<string>
#define N 100000
using namespace std;
int main() {
FILE *fp,*v5;
int n=0,c;
unsigned char str[N + 1],a,b;
fp = fopen("findme.exe", "rb");
v5 = fopen("real.exe", "wb");
while ( feof(fp) ==0)
{
n++;
a=fgetc(fp);
//break;
b=a;
if(n>0x2440)
{
if(n%4==1)
{
fputc(b, v5);
}
}
}
//操作结束后关闭文件
fclose(fp);
fclose(v5);
return 0;
}
如我把这个代码放进一个名为CAOGAO项目里面,然后再把findme拖进其所在的文件夹里面
然后再vs2022里面直接运行就可以了,那个real.exe程序就是我们提取出来的文件了(注意是32位的)
打开我们可以看到,里面有很多的0C7h花指令,数量非常多那么我们就要用脚本去把花指令给去掉:
startaddr = 0x401068 #起始位置
endaddr = 0x401236#终点位置
for i in range(startaddr,endaddr):
if get_wide_byte(i) == 0xC7:#需要去除掉花指令
patch_byte(i,0x90)#nop指令的16进制为90h
print("[+] Addr {} is patched".format(hex(i)))
然后在函数开始的地方按U,P,F5就可以得到程序了
输出正确的条件是 byte_403490[v5]
与 byte_402148[v5]
的值相等。
可以看到这里的加密是一段rc4加密
密钥初始化没问题,但是在rc4加密的地方有魔改,多了一个换位
1 #define _CRT_SECURE_NO_WARNINGS 1
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include<bits/stdc++.h>
6 using namespace std;
7 void rc4(unsigned char* key, unsigned long key_length, unsigned char* data,
unsigned long data_length) {
8 unsigned char s[256] ;
9 int k[256];
10
11 for (int i = 0; i < 256; i++) {
12 s[i] = 256 - i;
13 k[i] = key[i % key_length];
14 }
15
16 for (int i = 0, j = 0; i < 256; i++) {
17 j = (j + s[i] + k[i]) % 256;
18 swap(s[i], s[j]);
19 }
20
21 int i = 0, j = 0, t = 0;
22 for (int n = 0; n < data_length; n++) {
23 i = (i + 1) % 256;
24 j = (j + s[i]) % 256;
25 swap(s[i], s[j]);
26 int t = (s[i] + s[j]) % 256;
27 data[n] -= s[256 - t];
28 }
29 }
30
31 int main() {
32 unsigned char key[] = "deadbeef";
33 unsigned char data[] = { 0x7D, 0x2B, 0x43, 0xA9, 0xB9, 0x6B, 0x93, 0x2D,
0x9A, 0xD0,
34 0x48, 0xC8, 0xEB, 0x51, 0x59, 0xE9, 0x74, 0x68, 0x8A, 0x45,
35 0x6B, 0xBA, 0xA7, 0x16, 0xF1, 0x10, 0x74, 0xD5, 0x41, 0x3C,
36 0x67, 0x7D };
37 unsigned long key_length =strlen((char*)key);
38 unsigned long data_length = strlen((char*)data);
39 rc4(key, key_length, data, data_length);
40
41 for (int i = 0; i < data_length; i++) {
42 printf("%c", data[i]);
43 }
44 printf("\n");
45 }
运行脚本就可解出来了
2.crackme:
64位的程序,直接用64位ida打开看看:
当看到main函数的末尾的时候发现程序突然就停止了,并且末尾有一个异常函数
打开流程图:
发现里面有很多的catc,try,而catch是不能被正常反调试,所以我们只能把这三处内存地址dump下来再用ida打开再来反编译:
int __fastcall sub_0(int a1, _DWORD *a2)
{
a2[9] += (a2[(a2[12] & 3) + 16] + a2[12]) ^ (a2[11] + ((a2[11] >> 5) ^ (16 * a2[11])));
return -14566;
}int __fastcall sub_0(int a1, _DWORD *a2)
{
a2[11] += (a2[((a2[12] >> 11) & 3) + 16] + a2[12]) ^ (a2[9] + ((a2[9] >> 6) ^ (32 * a2[9])));
return -14608;
}int __fastcall sub_0(int a1, int a2)
{
*(_DWORD *)(a2 + 48) ^= *(_DWORD *)(a2 + 60);
return -14610;
}
把这三段catch弄出来就是这个样子,然后就可以推断出是xtea加密,并且有一个地方有魔改
然后就是写脚本了:
#include <stdio.h>
#include <stdint.h>
#include<iostream>
using namespace std;
void decrypt ( unsigned int* v, unsigned int* k) {
unsigned int v0=v[0], v1=v[1];
unsigned int delta=857870677;
unsigned int sum=0, i;
for(i=0;i<32;i++)
{
sum^=delta;
}
for (i=0; i<32; i++) {
sum ^= delta;
v1 -= (((v0 >> 6) ^ ( v0 << 5 )) + v0) ^ (k[(sum >> 11) & 3] + sum);
v0 -= (((v1 >> 5) ^ (16 * v1)) + v1) ^ (k[sum & 3] + sum); //解密时将加密算法的顺序倒过来,还有+=变为-=
}
v[0]=v0; v[1]=v1;//解密后再重新赋值
}
int main()
{
unsigned int v[8];
v[0] = 0x32FC31EA;
v[1] = 0xF0566F42;
v[2] = 0xF905B0B2;
v[3] = 0x5F4551BE;
v[4] = 0xFB3EFCBB;
v[5] = 0x6B6ADB30;
v[6] = 0x4839879;
v[7] = 0x2F4378DF;
unsigned int k[4]={1234,2345,3456,4567};
for(int i=0;i<8;i+=2)
{
decrypt(v+i, k);
}
unsigned char a;
for(int i=0;i<8;i++)
{
for(int k=0;k<4;k++)
{
a=*((unsigned char *)(&v[i])+k);
printf("%c",a);
}
}
return 0;
}
3.mystery:
die打开可以看到是一个操作系统是ubuntu的应用,先用ida打开看一看:
可以看到main函数里面什么也没有,只有一个ptrace PTRACE_ATTACH,这个函数在这里的作用是反调试:
跟踪自己ptrace:因为,一个进程在同一个时间只能被一个进程跟踪。如果在启动的时候,就调用了这个ptrace PTRACE_ATTACH跟踪了自己,那么这个进程将无法被其他进程附加。
直接shift + F12查看发现有如Wrong!please try again! 这样的话,那么我们就点进去交叉引用就找到一个sub_1100的函数
通过分析代码可以发现s2应该就是我们的密文,然后sub_1500里面引用s1(我们输入的值),那么就可以发现sub_150就是我们的加密函数,然后sub_13E0的第一个参数是S盒,第二个参数是key;
对sub_13E0进行引用,发现还有一个地方引用了的:
然后发现是sub_1220函数
这个函数对我们的key进行了修改,那么我们就先把key解出来:
1 //dec_key
2 #include <bits/stdc++.h>
3 using namespace std;
4 void init(unsigned char *s, unsigned char *key, unsigned long len)
5 {
6 int t[256] = {0};
7 char tmp = 0;
8 for (int i = 0; i < 256; ++i)
9 {
10 s[i] = i;
11 t[i] = key[i % len];
12 }
13 int j = 0;
14 for (int i = 0; i < 256; ++i)
15 {
16 j = (j + s[i] + t[i]) % 256;
17 swap(s[i], s[j]);
18 }
19 }
20 void crypt1(unsigned char *s, unsigned char *data, unsigned long len)
21 {
22 int i = 0, j = 0, t = 0;
23 for (int k = 0; k < len; ++k)
24 {
25 i = (i + 1) % 256;
26 j = (j + s[i]) % 256;
27 swap(s[i], s[j]);
28 t = (s[i] + s[j]) % 256;
29 data[k] ^= s[t];
30 }
31 }
32
33 unsigned char key1[] = "keykey";
34 unsigned char key[] = "ban_debug!";
35 unsigned char s[256];
36
37 void decrypt_key()
38 {
39 int len = strlen((char*)key1);
40 init(s, key1, len);
41 len = strlen((char*)key);
42 crypt1(s, key, len);
43 for (int i = 0; i < strlen((char*)key); i++)
44 {
45 printf("%d, ", key[i]);
46 }
47 printf("\n");
48 }
49 int main()
50 {
51 memset(s, 0, sizeof(s));
52 decrypt_key();
53 memset(s, 0, sizeof(s));
54 }
55
56 //key[] = {105, 13, 90, 178, 64, 234, 25, 63, 47, 106};//exp
2 #include <bits/stdc++.h>
3 using namespace std;
4 void init(unsigned char *s, unsigned char *key, unsigned long len)
5 {
6 int t[256] = {0};
7 char tmp = 0;
8 for (int i = 0; i < 256; ++i)
9 {
10 s[i] = i;
11 t[i] = key[i % len];
12 }
13 int j = 0;
14 for (int i = 0; i < 256; ++i)
15 {
16 j = (j + s[i] + t[i]) % 256;
17 swap(s[i], s[j]);
18 }
19 }
20 void crypt(unsigned char *s, unsigned char *data, unsigned long len)
21 {
22 int i = 0, j = 0, t = 0;
23 char tmp;
24 for (int k = 0; k < len; ++k)
25 {
26 i = (i + 1) % 256;
27 j = (j + s[i]) % 256;
28 swap(s[i], s[j]);
29 t = (s[i] + s[j]) % 256;
30 data[k] += s[t]; //魔改rc4
31 }
32 }
33 unsigned char cipher[] = {80, 66, 56, 77, 76, 84, 144, 111, 254, 111, 188, 105,
185, 34, 124, 22, 143, 68, 56, 74, 239, 55, 67, 192, 162, 182, 52, 44};
34 unsigned char key[] = {105, 13, 90, 178, 64, 234, 25, 63, 47, 106};
35 unsigned char s[256];
36 int main()
37 {
38 int len = strlen((char*)key);
39 init(s, key, len);
40 len = strlen((char*)cipher);
41 crypt(s, cipher, len);
42 puts((char*)cipher);
43 return 0;
44 }
然后再把结果算出来就好了
4.encrypt:
用ida打开发现里面全部都是API
通过查询可以得知:是个标准的AEX—CBC加密
BCryptOpenAlgorithmProvider
函数的作用是打开指定的密码算法提供程序,使得应用程序可以使用该程序所提供的密码算法进行加密、解密等操作。具体来说,该函数用于初始化一个算法对象,以便后续使用其进行各种加密操作。
这里的作用是在解读字符串“ChainingModeCBC”
可以看见这里这个就是key
这一块根据查询可以得知,这里就是iv所在的地方
然后在网上找工具直接解就行了。
Comments | NOTHING