一个人的角落,也许并没人会看到这里~~ 祝福你,工作顺心,学习快乐~

逆向

一例MusicBox的固件简单分析,基于STM32芯片固件分析总结(待续)

从硬件到软件,制作一个高还原性,高保真的音乐盒子一直是我的兴趣之一。因此,我尝试在淘宝买一些音乐盒子做为设计参考,从双轨正负电压供电电路,电池充放电电路,stm32核心电路,到dac的解码电路,前极放大电路。到USB声卡,sdcard播放等功能。

最近发现某款音乐播放器的固件很有趣,因此,我在这简单记录一下分析过程,顺便总结一下从中学到的一些分析经验。

固件是通过SDcard更新的,商家发布新固件后,将固件放入SDcard后,芯片上的bootloader会检测并触发更新。

固件的部分内容如下:

bin-img

经过分析,固件使用了简单的压缩,一来减少固件体积,二是有校验机制。

通常,固件前一部分内容是,固件定义的栈顶指针以及芯片的中断向量表,均为4字节对齐。

CISCN(2018)逆向之task-reverse_06

午睡的时候,朋友发来个题,反正闲也闲着,来练练手。

#1 查壳

拿到程序先确认使用的是什么编译器,什么环境下运行,以决定用何种工具。

1525058201289

程序无花无壳,直接上IDA静态了,CTF的题在实机调比较方便。

北理研究生CTF Reverse 之 mips

这次北理面向在读研究生举办CTF大赛,直接线下赛,时长12小时,其中选择填空1小时,关卡题2小时(之后加时2小时),9小时攻防,攻防赛题在先知安全有提到。

由于第一届,邀请的学校队伍属于中等偏下水平。最后,24支队伍只有9个分数为正,另有近一半左右队伍线下攻防没有拿分。

主办方声称原则上不提供外网环境。

逆向题只有一道,而且为mips架构第一次遇到。手上没有运行环境,只能静态调,花了一个多小时才搞清楚流程,之后时间不够只能做罢,后来发现当场也没有人做出。

赛后再分析一遍其实还是挺简单的。

先附上解密代码,回舍,日后有时间再补。

程序: mips

gdb-reverse-key

#include <stdint.h>
#include <stdio.h>


void dec(uint32_t *val, uint32_t *k)
{
	uint32_t delta = 0x9e3779B9;
	uint32_t sum = 0xb8ab04e8;
	uint32_t v1 = val[1], v0=val[0];
	for(int i = 0; i < 40; i++)
	{
		v1 -= ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + k[(sum >> 11) & 3]);
		sum -= delta;
		v0 -= ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + k[sum & 3]);
	}
	printf("0x%x~~~\n", sum);
	val[0] = v0;
	val[1] = v1;

	return ;

}
int main()
{
	uint32_t key[4]={
		0x2bc12411, 0x0deadbee, 0x0276630b, 0x014f53f5
		};
	uint32_t value[]={
		0x9a5e3731, 0x2ed28785,
		0xeb26da7d, 0x82b06241,
		0x21d9dcd4, 0x44bdda49,
		0x15f62308, 0x7b0546ee,
		0xf6b4a519, 0x71c0d531
		};
	for(int i =0; i< 10; i+=2)
	{
		dec(&value[i],key);
	}
	printf("%s\n", value);
	//printf("0x%8x, 0x%8x\n", value[0], value[1]);
	return 0;
	
}

华师大CTF逆向题分析之Draw It(Monster)

Draw It(Monster)

程序打开运行界面:

draw_it_1

查壳发现为UPX压缩壳,UPX壳代码是开源的,加壳脱壳是同一个程序。

draw_it_2

手脱ESP定律,或者往下找popad接着一个大跳可以直接到程序OEP。 手脱比较节省时间,但是有一些区段或者其它信息没法还原。

draw_it_3

脱壳之后用IDA分析来到程序消息处理函数找到关键位置:

draw_it_4

通过分析,程序取所画图片的连续相同的点的个数与cmp数据做对比, 猜测cmp数据为Flag相关数据,存储了Flag图片的一些信息,即bitmap方式连续相同的点的个数。 因为位图是24位,每个像素点用3位来存储,所以比较的时候需要乘3。

导出数据:

draw_it_5

进一步验证,将数据全部相加得到30000(50*600),确定了之前的分析。

编写Win32程序,解析数据:

int sum=0,cmp_i=0,
for(int i=0;i<50;i++)
{
	for(int j=0;j<600;j++)
	{
		sum++;
		if(sum < cmp[cmp_i])
		{
			if(  odd )
				SetPixel(hdc,j, 50-i,RGB(255,0,0));//BMP从上到下,从左到右存贮
		}
		else
		{
			sum = 0;
			odd = !odd;
			all+=cmp[cmp_i] ;
			cmp_i++;
			
		}

	}
}

可以得到结果:

draw_it_6

华师大CTF逆向题分析之巴黎解密

预赛逆向题有三道 第一道为巴黎解密ctf文件 第二道为画出FLAG 第三道为Stephen

决赛逆向题有四道,只做出了前两题。 第一题为MFC程序跑不起来 第二道为Elf64、STL对素数表加密 第三道使用 VirtualProtect 反调试。 第四道使用了一个linux程序对数据进行封装,没时间做。 前两道相对简单

巴黎解密ctf文件

有个文件加密工具,能将一个文件加密到一个.ctf文件中去。

有一个犯罪分子将存有犯罪记录的一个名为“CTFtest.ctf” 的加密文件被删除了。现经过数据恢复,我们已经恢复了该文件。

但是很不幸,该文件头部的部分数据已经被覆盖掉了。这个.ctf文件已经不能正常打开了。 而且加密该文件的口令,犯罪分子也不愿意交代,我们只知道他惯用的口令是一个8位纯数字口令。

请选手下载http://ctf.ecnu.edu.cn/question/attachment1.zip

通过其中的.ctf文件以及解密程序最大限度地恢复出文件中的内容,flag就在里面。 Flag形式为大写32位md5。

题目给出了一个解密程序以及一个加密后丢失了一部分文件头的文件

如图:

final_re_1

目测丢失了前35bytes的数据

解密程序无壳无花,直接IDA,MFC静态库编译。

结合导入表以及程序运行来看,调用了CreateFile、ReadFile、MessageBox等参数,

顺利跟踪到了程序关键地址 0x402570 分析函数,局部变量比较多,

final_re_2

应该八九不十了。 接着分析:

final_re_3

程序打开文件,判断前4 bytes 内容为 0x33465443 转换为字符CTF3

final_re_4

接着读4bytes转为DWORD型,为接下来要读取的长度并存储。 接着读文件16字节,取密码框内容, 将密码进行两次MD5加密,将结果与取到的16字节进行对比。

final_re_5

接着读4bytes转为DWORD型,做为接下来要读取的长度,再次读取,然后关闭文件。

至此,加密文件全部读取完毕,小结一下文件结构:

4 bytes 为固定字符‘CTF3’
4 bytes 为len of head
{...}   为head
16 bytes 将密码经两次MD5加密的密文
4 bytes 为len of body
{...}   为body

此时回过头来分析.ctf加密文件内容。

final_re_6

发现偏移为0x29位置4bytes的内容为0x0000619C,这一部分正好对应为文件此后的长度, 可以推定为len_of_body存储位置。向前16bytes为MD5密文区域,并且只有6bytes保留。

根据提示,密码为8位数字,通过这一部分MD5,应该可以还原。 编写程序:

#include <stdio.h>
#include <windows.h>
#include "md5.h"

unsigned char data[6]={0x48,  0xB1,  0xED,  0x05,  0x8D,  0xF7 };

int main()
{
	unsigned char  a[100] = {0},b[17] = {0},c[17] = {0};
	int num = 0, i=0;

	for( num = 10000000; num < 99999999; num++){
		_itoa(num,(char *)a, 10);
		MD5_CTX md5;

		MD5Init(&md5);                
		MD5Update(&md5,a,strlen((char *)a));  
		MD5Final(&md5,b);
		
		MD5Init(&md5);                
		MD5Update(&md5,b,16);  
		MD5Final(&md5,c);

		i=0;
		while(data[i] == c[i+10])
		{
			i++;
			if(i>=6)
				goto l;
		}
	}
l:
	printf("%d", num);
	getchar();
	getchar();
	system("pause");
	return 1;

}

程序跑出密码为20160610。 此时还剩11bytes的head内容不知道。

final_re_7

接着查找程序对head部分的引用,发现程序对head沁使用多字节字符转宽字符库函数。 进行字符串拼接之后,传入CreateFile。 由此可以断定,head部分内容为加密文件的文件名。

至此我们可以对加密文件的分析,基本结束,将文件头丢失部分恢复,Head部分随便指定一个文件名。 解密程序将文件恢复:

final_re_8

得到一个压缩包文件,查看内容为Word文件,打开得到Flag。

final_re_9