查看原文
其他

安全浏览器历史记录数据库解密算法逆向

旺仔_小可爱 看雪学苑 2024-07-16



逆向环境搭建


我的逆向环境是Win10 x64逆向的产品是64位的某安全浏览器15.3.2075.64版本,版本我会放到附件里面,逆向的原因是需要做取证。





定位数据库解密算法


我的方法是通过对CreateFile下断点拿到句柄,然后通过句柄来对ReadFile进行过滤,当ReadFile读取到内容后,对内容进行下内存写入断点。


1.对Createfile下断点获取句柄


2.通过句柄来对ReadFile进行过滤


3.当ReadFile读取到内容后对内容下内存写入断点


4.当内存断点命中时就是算法的位置所在的模块是Chrome.dll偏移0x7876C00





分析数据库解密算法


接下来在IDA中对算法进行分析,在分析之前需要对常见的算法特征进行了解,我的分析结果是一个AES算法。


其中AES的KEY和IV都是通过MD5进行计算的,IV是固定值,KEY需要进行逆向分析。



如果不知道算法的特征,可以将0x0C6A56363这种值进行百度。





下面代码在Chrome.dll中偏移0x787740,这是我对数据库解密算法的分析结果。



在动态调试器中找到Chrome.dll中偏移0x787740的位置,对我们已经分析出来的函数进行命名。



可以看到计算完成第一个MD5得到结果是F2 A6 73 A0 A6 E1 B9 9C F6 BA B3 DB F2 37 2B 0A。



第二个MD5得到结果是20 D7 42 0F 9C 37 A3 5D CA 6F E9 2A 1C 69 99 A9 这是IV。



F2 A6 73 A0 A6 E1 B9 9C F6 BA B3 DB F2 37 2B 0A 和 20 D7 42 0F 9C 37 A3 5D CA 6F E9 2A 1C 69 99 A9做为参数传递给了AES_Initialization



解密前的数据是我们ReadFile读取出来的内容:



解密后的数据是Sqlite3的文件标识,到这里数据库解密完成。





实现数据库解密算法


1.将ReadFile读取的数据拷贝过来


2.使用OPENSSL库的AES算法对算法进行复现


3.解密结果和原程序一样


#define AESKEY "F2A673A0A6E1B99CF6BAB3DBF2372B0A"   //密钥
#define AESIV "20D7420F9C37A35DCA6FE92A1C6999A9"    //初始向量  (固定的)

void AesFun_360()
{
AES_KEY decryptkey;
unsigned char *key = str2hex(AESKEY);
unsigned char *stdiv = str2hex(AESIV);
AES_set_decrypt_key(key,128,&decryptkey); ////将文本形式的HEX串进行转换
unsigned char tmpiv[16];
memcpy(tmpiv,stdiv,16);
unsigned char decrypted_text[4096];
memset(decrypted_text,0,4096);
AES_cbc_encrypt(data, decrypted_text,4096,&decryptkey,tmpiv,AES_DECRYPT);
OutputHex(decrypted_text,4096); ////输出HEX
}



获取KEY和IV的MD5计算参数并复现


计算KEY的参数是AF 58 5C B1 7A 03 3E 79 BF 1E 67 DE 9D 6F 17 82 01 00 00 00 73 41 6C 54



计算的结果是F2 A6 73 A0 A6 E1 B9 9C F6 BA B3 DB F2 37 2B 0A



计算IV的参数是E8 3D 01 00 19 32 64 45 A7 FD BE 7A 31 17 2B 5F




计算的结果是20 D7 42 0F 9C 37 A3 5D CA 6F E9 2A 1C 69 99 A9




//key的算法
uint8_t data1[0x18] = { 
0xAF, 0x58, 0x5C ,0xB1 ,0x7A ,0x03 ,0x3E ,0x79 ,0xBF ,0x1E ,0x67 ,0xDE ,0x9D ,
0x6F ,0x17 ,0x82 ,0x01 ,0x00 ,0x00 ,0x00 ,0x73 ,0x41 ,0x6C ,0x54 };
hash_context ctx;
uint8_t hash1[20];
hash_start(&ctx);
hash_update(&ctx, data1, 0x18);
hash_finish(&ctx, hash1);
system("pause");

//这是IV的算法
uint8_t data1[0x10] = { 0xE8, 0x3D, 0x01, 0x00, 0x19, 0x32, 0x64, 0x45, 0xA7, 0xFD, 0xBE, 0x7A, 0x31, 0x17, 0x2B, 0x5F };
hash_context ctx;
uint8_t hash1[20];
hash_start(&ctx);
hash_update(&ctx,data1,0x10);
hash_finish(&ctx,hash1);



获取IV计算参数的来源并复现


接下来先看看E8 3D 01 00 19 32 64 45 A7 FD BE 7A 31 17 2B 5F的算法,因为这个算法比较简单。


经过分析发现算法就在计算IV的MD5Fun函数里面。



下面就是算法的代码,这个算法是一个完整的函数,被内联优化了。算法函数有2个参数,第一个是要计算的值,第二个是接收计算结果的内存。



由于算法比较复杂,这里直接将汇编拷贝到代码里面进行调用。



算法函数的参数是一个固定的数字1,所以这个IV是固定值。





获取KEY计算参数的来源并复现

接下来看看AF 58 5C B1 7A 03 3E 79 BF 1E 67 DE 9D 6F 17 82 01 00 00 00 73 41 6C 54的算法。

经过分析AF 58 5C B1 7A 03 3E 79 BF 1E 67 DE 9D 6F 17 82 01 00 00 00 73 41 6C 54是由3个部分组成的。


第一个部分是AF 58 5C B1 7A 03 3E 79 BF 1E 67 DE 9D 6F 17 82这是最重要的一个密钥。


第二个部分是01 00 00 00 这是通过一个简单的算法算出来的,算法的参数是1。


第三个部分是73 41 6C 54 这是一个固定值。



下面是对第二个部分01 00 00 00算法的复现:



GetMD5_KEY_Data proc
 sub rsp,98h
 mov byte ptr[rdx + 0],cl
 mov byte ptr[rdx + 1],ch
 mov eax, ecx
 shr eax, 10
 mov byte ptr[rdx + 2],al
 mov eax, ecx
 shr eax, 18
 mov byte ptr[rdx +3],al
 add rsp,98h
 ret          
GetMD5_KEY_Data endp

接下来对第一个部分AF 58 5C B1 7A 03 3E 79 BF 1E 67 DE 9D 6F 17 82的算法进行定位分析复现。

由于过程内容太多,具体细节进行省略,大概就是通过对R9的基址进行追踪,然后内存访问断点进行定位。



下面是定位到的算法位置是chrome.dll 中偏移0x7877BEF。



在IDA中查看算法的全部样貌,可以看到该算法多次进行计算MD5。



首次参与计算MD5的值是{ 28 BF 4E 5E 4E 75 8A 41 64 00 4E 56 FF FA 01 08 

2E 2E 00 B6 D0 68 3E 80 2F 0C A9 FE 64 53 69 7A } 这个值是固定的。



在算法函数的中间部分出现了1313f621f81ec8be54a1edbc93408161这个值需要进行逆向分析。



算法函数中的sub_7877250也是一个算法,需要进行分析。



sub_7877250函数的还原结果:



void sub_7877250(uint8_t *pn1,uint8_t *pn2,uint8_t *pn3)
{
uint8_t u1[0x100] = { 0 };
memset(u1,0xAA,0x100);
//****************************************************************************************************************************
char u2[0x10] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
for (size_t i = 0;i < 0x100;i = i + 0x10)
{
for (size_t j = 0; j < 0x10; j++)
{
u1[i + j] = u2[j];
}
for (size_t j = 0; j < 0x10; j++)
{
u2[j] += 0x10;
}
}
//****************************************************************************************************************************
uint8_t cl = 0;
for (size_t eax = 0; eax < 0x100; eax++)
{
uint8_t dl = u1[eax];
cl = cl + dl;
uint8_t r8d = eax + 0xF;
if (eax >= 0) r8d = eax;
r8d = r8d & 0xFFFFFFF0;
uint8_t r9d = eax;
r9d = r9d - r8d;
cl = cl + pn1[r9d];
r8d  = cl;
r9d = u1[r8d];
u1[eax] = r9d;
u1[r8d] = dl;
}
//****************************************************************************************************************************
uint8_t cl1 = 0;
uint8_t edx = 0;
for (size_t i = 0; i < 0x20; i++)
{
uint8_t r8d = edx + 1;
uint8_t r9d = edx + 0x100;
if (r8d >= 0) r9d = r8d;
edx = edx - (r9d & 0xFFFFFF00) + 1;
r8d = edx;
r9d = u1[r8d];
cl1 = cl1 + r9d;
uint8_t r10d = cl1;
uint8_t r11d =  u1[r10d];
u1[r8d] = r11d;
u1[r10d] = r9d;
r9d = r9d + u1[r8d];
r8d = r9d;
r9d = pn2[i];
r9d = r9d ^ u1[r8d];
pn3[i] = r9d;
}
//***************************************************************************************************************************
return;
}


AF 58 5C B1 7A 03 3E 79 BF 1E 67 DE 9D 6F 17 82算法函数的还原结果。



void Get_82176F9DDE671EBF793E037AB15C58AF_Fun()
{
//****************************************************************************************************************************
uint8_t data1[0x20] = 

0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, //固定
0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A
};
hash_context ctx;
uint8_t hash1[20];
hash_start(&ctx);
hash_update(&ctx,data1,0x20);
hash_finish(&ctx,hash1);
for (size_t i = 0;i < 50;i++)
{
hash_start(&ctx);
hash_update(&ctx,hash1,0x10);
hash_finish(&ctx,hash1);
}
//****************************************************************************************************************************
uint8_t data00[0x10] =
{
0x5A,0x00,0x34,0x4F,0x40,0xD0,0xA5,0xC5,0x2B,0x16,0x0B,0x83,0x0E,0x6E,0x08,0x6E //固定
};
uint8_t data01[0x10] =
{
0x5A,0x00,0x34,0x4F,0x40,0xD0,0xA5,0xC5,0x2B,0x16,0x0B,0x83,0x0E,0x6E,0x08,0x6E //固定
};
//Get_1313f621f81ec8be54a1edbc93408161_Fun 不固定
uint8_t data02[0x20] =
{
0x31,0x33,0x31,0x33,0x66,0x36,0x32,0x31,0x66,0x38,0x31,0x65,0x63,0x38,0x62,0x65,  //1313f621f81ec8be54a1edbc93408161
0x35,0x34,0x61,0x31,0x65,0x64,0x62,0x63,0x39,0x33,0x34,0x30,0x38,0x31,0x36,0x31  
};
uint8_t data03[0x20] =
{
0x31,0x33,0x31,0x33,0x66,0x36,0x32,0x31,0x66,0x38,0x31,0x65,0x63,0x38,0x62,0x65,  //1313f621f81ec8be54a1edbc93408161
0x35,0x34,0x61,0x31,0x65,0x64,0x62,0x63,0x39,0x33,0x34,0x30,0x38,0x31,0x36,0x31
};
for (size_t i = 0; i < 20; i++)
{
for (size_t j = 0; j < 16; j++)
{
data01[j] = data00[j] ^ i;
}
sub_7877250(data01,data02,data02);
}
//****************************************************************************************************************************
hash_start(&ctx);
hash_update(&ctx,data03,0x20);
hash_update(&ctx,data02,0x20);
hash_finish(&ctx,hash1);

for (size_t i = 0; i < 50; i++)
{
hash_start(&ctx);
hash_update(&ctx,hash1,0x10);
hash_finish(&ctx,hash1);
}
//****************************************************************************************************************************
system("pause");
}


下面是还原后的算法运行结果和原程序的算法运行结果。



接下来对1313f621f81ec8be54a1edbc93408161的算法进行定位分析复现。

定位到算法的位置是在chrome.dll中的偏移0x71DBC39,是通过把D4 0B 30 BB 38 FB 92 DC等数值进行计算MD5。



计算结果出现的位置是在chrome.dll中偏移0x71DB059。



下面是算法的代码:



void Get_1313f621f81ec8be54a1edbc93408161_Fun()
{
hash_context ctx;
//调用Get_D40B30BB38FB92DCC8ADE2A96592A54F获取ecx的计算方式
uint8_t ecx[] = {
0xD4, 0x0B, 0x30, 0xBB, 0x38, 0xFB, 0x92, 0xDC, 0xC8, 0xAD, 0xE2, 0xA9, 0x65, 0x92, 0xA5, 0x4F,
0xB4, 0x22, 0x1C, 0x46, 0xF2, 0xFA, 0x19, 0x52, 0xAA, 0x21, 0x7B, 0x4C, 0x90, 0xBC, 0x79, 0x5D,
0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22, 0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22,
0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22, 0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22,
0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22, 0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22,
0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22, 0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22,
0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22, 0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22,
0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22, 0x50, 0x68, 0x4F, 0xB3, 0x65, 0xA9, 0x90, 0x22,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
hash_start(&ctx);
hash_update(&ctx,ecx,0xC0);
hash_finish(&ctx,ecx);
}


下面是算法的运行结果:


接下来对0xD4,0x0B,0x30,0xBB,0x38,0xFB,0x92,0xDC,0xC8,0xAD,0xE2,0xA9,0x65,0x92,0xA5,0x4F的算法进行定位分析复现

定位到算法的位置是在chrome.dll中的偏移0x71DEE4A,需要的参数是181b1561c5d041373526cd9544d018e0。



下面是算法的代码:



void Get_D40B30BB38FB92DCC8ADE2A96592A54F_Fun()
{
char data[0x80] =
{
0x31,0x38,0x31,0x62,0x31,0x35,0x36,0x31,0x63,0x35,0x64,0x30,0x34,0x31,0x33,0x37,
0x33,0x35,0x32,0x36,0x63,0x64,0x39,0x35,0x34,0x34,0x64,0x30,0x31,0x38,0x65,0x30,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
//调用Get_181b1561c5d041373526cd9544d018e0_Fun() 获取181b1561c5d041373526cd9544d018e0
char r9[0x1F] =
{
0x31,0x38,0x31,0x62,0x31,0x35,0x36,0x31,0x63,0x35,0x64,0x30,0x34,0x31,0x33,0x37,
0x33,0x35,0x32,0x36,0x63,0x64,0x39,0x35,0x34,0x34,0x64,0x30,0x31,0x38,0x65
};
char*rdx = (char*)data;
char* r14 = (char*)0x80 + (DWORD64)rdx;
for (size_t i = 0x80; i > 0; i = i - 8)
{
char*rbx = (char*)rdx + 4;
if (Sub71DF130(1, rdx, rbx, r9) == 0 || rbx + 4 >= r14) break;
rdx = rbx + 4;
}
}


下面是还原后的算法运行结果和原程序的算法运行结果。




接下来对181b1561c5d041373526cd9544d018e0的算法进行定位分析复现。

定位到算法的位置是在chrome.dll中的偏移0x71DCF63,需要的参数是2B 40 00 80 43 4A B2 51 69 47 8F 45 D3 87 9A 9F 12 66 F0 EA BE B6 A4。



计算结果出现的位置是在chrome.dll中偏移0x71DB059



下面是算法的代码:



接下来对2B 40 00 80 43 4A B2 51 69 47 8F 45 D3 87 9A 9F 12 66 F0 EA BE B6 A4的算法进行定位分析复现。

定位到算法的位置是在chrome.dll中的偏移0x71DC6A0 需要的参数是YeND6A1s2Ws%3d 其他的是固定的。



下面是算法的代码:


接下来对YeND6A1s2Ws%3d 的算法进行定位分析复现。

定位到算法的位置是在chrome.dll中的偏移0x71DB7E0 需要的参数是61 E3 43 E8 0D 6C D9 68。


该算法是一个Base64 然后将结果进行URL编码。



下面是算法的代码:



char base64String[1000] = { 0 };
unsigned char byteArray[] = { 0x61,0xE3,0x43,0xE8,0x0D,0x6C,0xD9,0x68 }; // 字节数组
int byteArrayLength = sizeof(byteArray) / sizeof(byteArray[0]);
base64_encode(byteArray,byteArrayLength,base64String,sizeof(base64String));
printf("Eecoded String: %s\n",base64String);

接下来对61 E3 43 E8 0D 6C D9 68的算法进行定位分析复现

定位到算法的位置是在chrome.dll中的偏移0x71DC350 需要的参数是AF 72 95 FB 55 F1 04 BC CE 91 D6 13 58 9D DD D4。


接下来对AF 72 95 FB 55 F1 04 BC CE 91 D6 13 58 9D DD D4的算法进行定位分析复现

定位到算法的位置是在chrome.dll中的偏移0x71DC31C 需要的参数是13 63 68 53 AC D4 CF 8C FF CE 7B 39 0F 4C 1D 4D。



接下来对13 63 68 53 AC D4 CF 8C FF CE 7B 39 0F 4C 1D 4D的算法进行定位分析复现

定位到算法的位置是在chrome.dll中的偏移0x71DC185 需要的参数是用户的SID和计算机的GUID+固定值。




下面是计算的MD5的结果,位置是在chrome.dll中的偏移0x71DB059。



接下来对30673c63-7b45-4408-9009-a411eeb8c24c的算法进行定位分析复现

通过读取注册表获取计算机的GUID码:





接下来对S-1-5-21-3254454131-857614641-1060188673-1001的算法进行定位分析复现

通过API:ConvertSidToStringsidw获取用户的sid:





总结流程图





看雪ID:旺仔_小可爱

https://bbs.kanxue.com/user-home-891053.htm

*本文为看雪论坛优秀文章,由 旺仔_小可爱 原创,转载请注明来自看雪社区



# 往期推荐

1、嵌入Python解释器的程序逆向

2、记由长城杯初赛Time_Machine掌握父子进程并出题

3、从Clang到Pass加载与执行的流程

4、OLLVM混淆源码解读

5、VMProtect保护壳爆破步骤详解(入门级)



球分享

球点赞

球在看



点击阅读原文查看更多

继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存