火狐浏览器收藏夹的hash校验分析
背景:随着firefox的不断更新,不知不觉间已经更新到了56.0.2版本。之前收藏夹一直都是好好的,但是突然某一天发现收藏夹设置不上了。于是进行了深入分析,于是就写下了这个文章,也算是冒泡下表示下存在。
我们先来看存在的问题是什么。直接上图。


通过图我们可以发现:favicons.sqlite数据库的表moz_pages_w_icons的page_url_hash字段对page_url进行了hash校验
同样的moz_icons表中的fixed_icon_url_hash也对icon_url进行了hash校验。
首先我们通过尝试乱写一个hash值会怎么样?运气好的话,可能不会产生什么影响。但是天公不做美,胡乱改了hash校验值之后
收藏夹的图标竟然就不正常了。这个蛋疼,看来非得研究下到底是如何hash的。
首先:不得不提的是,如果能猜出来的话,坚决就不要去浪费时间分析。好的。
我们一看就首先会想到crc32,可惜的是,结果根本对不上,那么肯定就不是crc32了,于是继续进行猜解
这里需要尝试的工具和算法分别是如图:

通过这个密码学工具没发现能有匹配上的hash值(其实这个工具猜也不行,因为这个不主要是计算hash值的)
于是又专门对进行hash计算的进行了匹配如下图:
结果可想而知,一个匹配的都没有。到这里说实话当时的想法想骂娘,还好我们都有讲素质的人,骂也没用。
于是深深的抽了一只烟,下定决心要搞它,看看到底是啥玩意的hash计算。在搞之前说个题外话,我觉的真的有必要
把目前所有的国际流行经典的加密解密等全部集合成一个工具。以后猜都好猜,不过这只能留给有心人了,估计不是asmer还真搞不来这事。
下来我们就要开搞了,开始进入加速模式了。
首先依照国际惯例,我们必须要找到firefox浏览器的安装目录下,到底是哪个dll或者哪个exe,或者说到底是哪个pe在负责hash计算。
当然还是ProcessMonitor这个niubility的工具了,进程名写firefox.exe 操作写WriteFile。(至于这个工具不做解释反正很是强大都是系统的一些注册表回调了 sfilter miniport等核心操作)。
然后打开firefox浏览器,增加个收藏夹,最后我们通过栈属性中调用的关系,最后定位到了xul.dll这个文件。
然而可恨的是什么呢?上图就知道了

可恨的是这个dll的体积竟然高达55.6MB,在茫茫的代码海洋中寻找到hash计算的函数断点,绝对不是一件轻松的事情。
不过还是得找。于是花了一两个小时的时间把xul.dll载入到ida中(时间太久了蛋疼)
通过ida的findcrypt2识别算法插件发现如下图:

总共有8个已知的加密算法,这些算法前面都验证过,都不是。只能真正的找hash函数并打断点了,各种投机取巧的策略都失败了。
于是开始搜索各种可能的字符串作为标记,最后在hash这个字符串上通过各种交叉引用找到了如下片段:

把这个结果和问题最开始一图的hash比较,那绝对的一模一样的。好了到这里核心问题算是解决了
出个结果图如下:

ok了冒泡完毕!还是那句话,这年头什么东西都越来越难了,不过只要静下心来,问题都可以去解决。
浏览器的各种加密来的更猛烈些吧。哥不怕你~
我们先来看存在的问题是什么。直接上图。


通过图我们可以发现:favicons.sqlite数据库的表moz_pages_w_icons的page_url_hash字段对page_url进行了hash校验
同样的moz_icons表中的fixed_icon_url_hash也对icon_url进行了hash校验。
首先我们通过尝试乱写一个hash值会怎么样?运气好的话,可能不会产生什么影响。但是天公不做美,胡乱改了hash校验值之后
收藏夹的图标竟然就不正常了。这个蛋疼,看来非得研究下到底是如何hash的。
首先:不得不提的是,如果能猜出来的话,坚决就不要去浪费时间分析。好的。
我们一看就首先会想到crc32,可惜的是,结果根本对不上,那么肯定就不是crc32了,于是继续进行猜解
这里需要尝试的工具和算法分别是如图:

通过这个密码学工具没发现能有匹配上的hash值(其实这个工具猜也不行,因为这个不主要是计算hash值的)
于是又专门对进行hash计算的进行了匹配如下图:
# | 算法 | 结果 | 结果(大写) | 长度 | 备注 |
---|---|---|---|---|---|
1 | md5 | 7f4c79817fabaeaa0e909754cfe655e7 | 7F4C79817FABAEAA0E909754CFE655E7 | 32 | 前16位: 小写:7f4c79817fabaeaa 大写:7F4C79817FABAEAA |
2 | sha1 | bae3c9c6409a80602f33799b18b49b9a2cdcc2a2 | BAE3C9C6409A80602F33799B18B49B9A2CDCC2A2 | 40 | |
3 | sha256 | 8dd0d3350e771893b901733c799eb4e0d6d5ec6393a8f4e1f29f353497f73617 | 8DD0D3350E771893B901733C799EB4E0D6D5EC6393A8F4E1F29F353497F73617 | 64 | |
4 | sha512 | da685f291d0bb664ed16a6c052d2379911b0145ed762cda135da4228c3b7334914a3a34767f6475d6e8d79fbd49b2fb704cfaeb97c65ea5ab8b388bf5c04fe1d | DA685F291D0BB664ED16A6C052D2379911B0145ED762CDA135DA4228C3B7334914A3A34767F6475D6E8D79FBD49B2FB704CFAEB97C65EA5AB8B388BF5C04FE1D | 128 | |
5 | adler32 | 3e90066a | 3E90066A | 8 | |
6 | crc32 | 7f1df95c | 7F1DF95C | 8 | |
7 | crc32b | 54c44ecd | 54C44ECD | 8 | |
8 | fnv132 | 72081c90 | 72081C90 | 8 | |
9 | fnv164 | e7837b6f0aa25bd0 | E7837B6F0AA25BD0 | 16 | |
10 | fnv1a32 | 7ef42152 | 7EF42152 | 8 | |
11 | fnv1a64 | 26fde1d5080a72b2 | 26FDE1D5080A72B2 | 16 | |
12 | gost | 8937e7d5f96b0a10a75101d38326291eafe129d0296d9ba3b46ae8bd03954a9f | 8937E7D5F96B0A10A75101D38326291EAFE129D0296D9BA3B46AE8BD03954A9F | 64 | |
13 | gost-crypto | f1ae905f3dc3e00f48f6341a2f6ee17a911fc2a44487dba5b3d52191caf917c0 | F1AE905F3DC3E00F48F6341A2F6EE17A911FC2A44487DBA5B3D52191CAF917C0 | 64 | |
14 | haval128,3 | da6b7922c8f2c2a0a4527c0e1c2c3527 | DA6B7922C8F2C2A0A4527C0E1C2C3527 | 32 | |
15 | haval128,4 | 9a2f738dba21363844a53e93fa733634 | 9A2F738DBA21363844A53E93FA733634 | 32 | |
16 | haval128,5 | 42d50658a8797e15debbb8b9f049a0da | 42D50658A8797E15DEBBB8B9F049A0DA | 32 | |
17 | haval160,3 | 3aaa82730af3184bb9d3cdef8930045f052aa771 | 3AAA82730AF3184BB9D3CDEF8930045F052AA771 | 40 | |
18 | haval160,4 | e1470f77599d96989273ea110b0eac473726faa7 | E1470F77599D96989273EA110B0EAC473726FAA7 | 40 | |
19 | haval160,5 | 92e5bf63f1eb6e0729789837a40a99baf9669eff | 92E5BF63F1EB6E0729789837A40A99BAF9669EFF | 40 | |
20 | haval192,3 | cecf625bca8e5c9d42029a39e1a9e7c0999bec518e87d7ec | CECF625BCA8E5C9D42029A39E1A9E7C0999BEC518E87D7EC | 48 | |
21 | haval192,4 | 58ba63fd0969d98d4e0f338c717436934b24cc59cdd0a628 | 58BA63FD0969D98D4E0F338C717436934B24CC59CDD0A628 | 48 | |
22 | haval192,5 | 3f4562d504b7e7eb55c0c885f7bda04fbdff7fb76c1d11fb | 3F4562D504B7E7EB55C0C885F7BDA04FBDFF7FB76C1D11FB | 48 | |
23 | haval224,3 | 2b983078b1bf7a1837a201b6e70b71922152fafebe7d25ced14cb7ae | 2B983078B1BF7A1837A201B6E70B71922152FAFEBE7D25CED14CB7AE | 56 | |
24 | haval224,4 | 7b8c0730275c2d320806fc86823aecbae93bbcab3109abceab9f0533 | 7B8C0730275C2D320806FC86823AECBAE93BBCAB3109ABCEAB9F0533 | 56 | |
25 | haval224,5 | d17c556996ed4593390acd7c2ca5b39b44a1186fb575ccfab1cb2131 | D17C556996ED4593390ACD7C2CA5B39B44A1186FB575CCFAB1CB2131 | 56 | |
26 | haval256,3 | 594a3f8339f591af11297a943141adea90fc3336fae44ccf0e90b0a4273c4126 | 594A3F8339F591AF11297A943141ADEA90FC3336FAE44CCF0E90B0A4273C4126 | 64 | |
27 | haval256,4 | 9cae8d5aeaed19b7ef3bb0540b81193ef39daea4b631050b6c05e392c4cd4a13 | 9CAE8D5AEAED19B7EF3BB0540B81193EF39DAEA4B631050B6C05E392C4CD4A13 | 64 | |
28 | haval256,5 | ff7f42518fc67d3d4a40f8f76696a6d963f1ff55c79962dfefaca13cadd82d4d | FF7F42518FC67D3D4A40F8F76696A6D963F1FF55C79962DFEFACA13CADD82D4D | 64 | |
29 | joaat | 843bd690 | 843BD690 | 8 | |
30 | md2 | ad63c4e08e817c3f8da0aff661a6277c | AD63C4E08E817C3F8DA0AFF661A6277C | 32 | |
31 | md4 | 94ee16a9bd52b09a2cb3d04b703acf48 | 94EE16A9BD52B09A2CB3D04B703ACF48 | 32 | |
32 | ripemd128 | d29ca082da0837424468ef35b2ab9831 | D29CA082DA0837424468EF35B2AB9831 | 32 | |
33 | ripemd160 | 06376f0b4541dd12212a08ac5f3348b315c9ef32 | 06376F0B4541DD12212A08AC5F3348B315C9EF32 | 40 | |
34 | ripemd256 | 242964e7c3f39b56229b4f5efcb38f00ea1c0205a865abec70348f96d1e79ab6 | 242964E7C3F39B56229B4F5EFCB38F00EA1C0205A865ABEC70348F96D1E79AB6 | 64 | |
35 | ripemd320 | f89b2dcb11b2bc99ff60dfdc8eb0cf50d169cbe7f68b945dcc6b3a70ada96d531777c07e9313a1c9 | F89B2DCB11B2BC99FF60DFDC8EB0CF50D169CBE7F68B945DCC6B3A70ADA96D531777C07E9313A1C9 | 80 | |
36 | sha224 | 60794256cb6fab46c4b7867c3548db250cd4ebde4d1beeada20053bb | 60794256CB6FAB46C4B7867C3548DB250CD4EBDE4D1BEEADA20053BB | 56 | |
37 | sha384 | 0babbc39788eb326edc3d8f7bbd37288bd699dd696fcf07ba1358311fd5fad35137e2b79e391dcb01622e7bdf1827e38 | 0BABBC39788EB326EDC3D8F7BBD37288BD699DD696FCF07BA1358311FD5FAD35137E2B79E391DCB01622E7BDF1827E38 | 96 | |
38 | snefru | ac7bb447a099b2ed17730779fe072f3749d71bb2dd45963de5bd864879d54ffd | AC7BB447A099B2ED17730779FE072F3749D71BB2DD45963DE5BD864879D54FFD | 64 | |
39 | snefru256 | ac7bb447a099b2ed17730779fe072f3749d71bb2dd45963de5bd864879d54ffd | AC7BB447A099B2ED17730779FE072F3749D71BB2DD45963DE5BD864879D54FFD | 64 | |
40 | tiger128,3 | aa235c032b41d4bc7f40b3ba3811a4e3 | AA235C032B41D4BC7F40B3BA3811A4E3 | 32 | |
41 | tiger128,4 | 5e0ab0723d5fe5c55c20acd5b2c2936f | 5E0AB0723D5FE5C55C20ACD5B2C2936F | 32 | |
42 | tiger160,3 | aa235c032b41d4bc7f40b3ba3811a4e350922fe8 | AA235C032B41D4BC7F40B3BA3811A4E350922FE8 | 40 | |
43 | tiger160,4 | 5e0ab0723d5fe5c55c20acd5b2c2936ff141f1a5 | 5E0AB0723D5FE5C55C20ACD5B2C2936FF141F1A5 | 40 | |
44 | tiger192,3 | aa235c032b41d4bc7f40b3ba3811a4e350922fe80703f9ee | AA235C032B41D4BC7F40B3BA3811A4E350922FE80703F9EE | 48 | |
45 | tiger192,4 | 5e0ab0723d5fe5c55c20acd5b2c2936ff141f1a578786293 | 5E0AB0723D5FE5C55C20ACD5B2C2936FF141F1A578786293 | 48 | |
46 | whirlpool | 11b50098eecbd14d84ae2f9c7c3834e269e4300845796839338a36d722615c8271a38c3586fbf61f5d82544b5782567733918f9c81491bba9bd1fd6c3a1b52bb | 11B50098EECBD14D84AE2F9C7C3834E269E4300845796839338A36D722615C8271A38C3586FBF61F5D82544B5782567733918F9C81491BBA9BD1FD6C3A1B52BB | 128 |
结果可想而知,一个匹配的都没有。到这里说实话当时的想法想骂娘,还好我们都有讲素质的人,骂也没用。
于是深深的抽了一只烟,下定决心要搞它,看看到底是啥玩意的hash计算。在搞之前说个题外话,我觉的真的有必要
把目前所有的国际流行经典的加密解密等全部集合成一个工具。以后猜都好猜,不过这只能留给有心人了,估计不是asmer还真搞不来这事。
下来我们就要开搞了,开始进入加速模式了。
首先依照国际惯例,我们必须要找到firefox浏览器的安装目录下,到底是哪个dll或者哪个exe,或者说到底是哪个pe在负责hash计算。
当然还是ProcessMonitor这个niubility的工具了,进程名写firefox.exe 操作写WriteFile。(至于这个工具不做解释反正很是强大都是系统的一些注册表回调了 sfilter miniport等核心操作)。
然后打开firefox浏览器,增加个收藏夹,最后我们通过栈属性中调用的关系,最后定位到了xul.dll这个文件。
然而可恨的是什么呢?上图就知道了

可恨的是这个dll的体积竟然高达55.6MB,在茫茫的代码海洋中寻找到hash计算的函数断点,绝对不是一件轻松的事情。
不过还是得找。于是花了一两个小时的时间把xul.dll载入到ida中(时间太久了蛋疼)
通过ida的findcrypt2识别算法插件发现如下图:

总共有8个已知的加密算法,这些算法前面都验证过,都不是。只能真正的找hash函数并打断点了,各种投机取巧的策略都失败了。
于是开始搜索各种可能的字符串作为标记,最后在hash这个字符串上通过各种交叉引用找到了如下片段:
int __stdcall sub_1072C31E(int a1, int a2, _DWORD *a3)
{
int result; // eax@1
int v4; // ecx@1
signed int v5; // ebx@3
int v6; // ecx@3
int v7; // eax@5
char *v8; // edi@9
int v9; // ecx@9
unsigned int k; // edx@9
int v11; // ecx@10
unsigned int v12; // esi@11
int v13; // edx@11
unsigned int v14; // ecx@11
int v15; // edx@12
int v16; // ST08_4@14
void *v17; // esi@14
int v18; // ecx@19
unsigned int l; // edx@19
int v20; // ecx@20
int v21; // ecx@23
unsigned int i; // edx@23
int v23; // ecx@24
int v24; // ecx@27
unsigned int j; // edx@27
int v26; // ecx@28
unsigned __int64 v27; // [sp-10h] [bp-BCh]@21
unsigned int v28; // [sp+Ch] [bp-A0h]@8
char *v29; // [sp+10h] [bp-9Ch]@8
char *v30; // [sp+14h] [bp-98h]@8
char *v31; // [sp+18h] [bp-94h]@8
int (__stdcall **v32)(int, int, int, int); // [sp+20h] [bp-8Ch]@8
_DWORD *v33; // [sp+24h] [bp-88h]@1
unsigned int v34; // [sp+28h] [bp-84h]@1
char *v35; // [sp+2Ch] [bp-80h]@8
char *v36; // [sp+30h] [bp-7Ch]@8
char *v37; // [sp+34h] [bp-78h]@8
const char *v38; // [sp+38h] [bp-74h]@8
int v39; // [sp+3Ch] [bp-70h]@8
__int16 v40; // [sp+40h] [bp-6Ch]@8
__int16 v41; // [sp+42h] [bp-6Ah]@8
char *v42; // [sp+44h] [bp-68h]@8
unsigned int v43; // [sp+48h] [bp-64h]@8
int v44; // [sp+4Ch] [bp-60h]@16
void *v45; // [sp+50h] [bp-5Ch]@7
char *v46; // [sp+54h] [bp-58h]@3
int v47; // [sp+58h] [bp-54h]@7
int v48; // [sp+5Ch] [bp-50h]@16
v33 = a3;
result = (*(int (__stdcall **)(int, int *))(*(_DWORD *)a2 + 12))(a2, (int *)&v34);
if ( result >= 0 )
{
if ( v34 - 1 <= 1 )
{
sub_1054CB92(v4);
v5 = 0;
(*(void (__stdcall **)(int, _DWORD, int))(*(_DWORD *)a2 + 36))(a2, 0, v6);
sub_1044E031((int)&v46);
if ( v34 > 1 )
(*(void (__stdcall **)(int, signed int, int *))(*(_DWORD *)a2 + 32))(a2, 1, (int *)&v46);
v7 = moz_xmalloc(64);
if ( v7 )
{
*(_WORD *)(v7 + 40) = 255;
*(_BYTE *)(v7 + 48) = 1;
*(_DWORD *)v7 = &off_124114B4;
*(_DWORD *)(v7 + 56) = 0;
}
else
{
v7 = 0;
}
sub_1083531E(&v45, v7);
if ( v47 )
{
v38 = "prefix_lo";
v39 = 9;
v40 = 33;
v41 = 2;
if ( (unsigned __int8)sub_1057CEA8((int)&v46, (int)&v38) )
{
v21 = 0;
for ( i = 0; i < v43; ++i )
{
v23 = __ROL4__(v21, 5);
v21 = -1640531527 * (*(_WORD *)&v42[2 * i] ^ v23);
}
HIDWORD(v27) = (unsigned __int16)v21;
LODWORD(v27) = 0;
}
else
{
v38 = "prefix_hi";
v39 = 9;
v40 = 33;
v41 = 2;
if ( !(unsigned __int8)sub_1057CEA8((int)&v46, (int)&v38) )
{
v5 = -2147467259;
if ( v45 )
sub_10939928(v45);
goto LABEL_16;
}
v24 = 0;
for ( j = 0; j < v43; ++j )
{
v26 = __ROL4__(v24, 5);
v24 = -1640531527 * (*(_WORD *)&v42[2 * j] ^ v26);
}
v27 = __PAIR__((unsigned __int16)v24, 0) + 0xFFFFFFFF;
}
}
else
{
v35 = v42;
v37 = v42;
v29 = v42;
v36 = &v42[2 * v43];
v30 = &v42[2 * v43];
v31 = &v42[2 * v43];
v40 = 33;
v41 = 2;
v32 = &off_123DC3FC;
v38 = ":";
v28 = (unsigned int)v42;
v39 = 1;
if ( sub_1061E6B1(
(int)&v35,
(int)&v38,
(int)&v29,
(int (__thiscall ***)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD))&v32) )
{
sub_105343D7((int)&v35, v28, (unsigned int)v37);
v8 = v35;
v9 = 0;
for ( k = 0; k < (unsigned int)v36; ++k )
{
v11 = __ROL4__(v9, 5);
v9 = -1640531527 * (*(_WORD *)&v35[2 * k] ^ v11);
}
v12 = (unsigned __int16)v9;
v13 = 0;
v14 = 0;
if ( v43 > 0 )
{
do
{
v15 = __ROL4__(v13, 5);
v13 = -1640531527 * (*(_WORD *)&v42[2 * v14++] ^ v15);
}
while ( v14 < v43 );
v8 = v35;
}
v16 = ((unsigned int)v13 + __PAIR__(v12, 0)) >> 32;
v17 = v45;
sub_1072C4E6((int)v45, v13, v16);
sub_105606C0(v8, (unsigned __int8)v37);
goto LABEL_15;
}
v18 = 0;
for ( l = 0; l < v43; ++l )
{
v20 = __ROL4__(v18, 5);
v18 = -1640531527 * (*(_WORD *)&v42[2 * l] ^ v20);
}
v27 = (unsigned int)v18;
}
v17 = v45;
sub_1072C4E6((int)v45, v27, SHIDWORD(v27));
LABEL_15:
*v33 = v17;
LABEL_16:
sub_105606C0(v46, v48);
sub_105606C0(v42, v44);
return v5;
}
result = -2147467259;
}
return result;
}
在这个上面打上断点,然后打开firefox.exe后挂载上,然后设置一个收藏夹,在经历接近半个小时的等待后发现的确是能断下来,但是跟了好几次(不小心就跑飞了),别小看这好几次,好几次X0.5小时 = 好几个小时。思想接近崩溃了。
在基本无奈之时,忽然想起来firefox不是开源的吗。哎呀我去。直接是浪费了时间。于是各种搜索
找到了firefox 56.0.2的下载版本。地址如下
http://releases.mozilla.org/pub/firefox/releases/56.0.2/source/firefox-56.0.2.source.tar.xz ;
下载解压如下图:

压缩文件1.5G解压后 n个G的大小,在这么多文件中找到hash也不是容易的事情。
于是下载了xsearch.exe (实际上EveryThing更好,但是木有下载)
看来上面的int __stdcall sub_1072C31E(int a1, int a2, _DWORD *a3)函数还是有用的
起码里面有 prefix_hi这个字符串,我们就按照这个来查询,如下图:

经过对查询到的每个文件进行快速感觉,最后发现了toolkit\components\places\SQLFunctions.cpp 文件,找到如下片段代码
从中我们发现出了算法的整个结构 以及核心的HashString的算法,我们再对HashString进行搜索发现了mfbt\HashFunctions.h
代码如下:
好了,这下根据
在这个上面打上断点,然后打开firefox.exe后挂载上,然后设置一个收藏夹,在经历接近半个小时的等待后发现的确是能断下来,但是跟了好几次(不小心就跑飞了),别小看这好几次,好几次X0.5小时 = 好几个小时。思想接近崩溃了。
在基本无奈之时,忽然想起来firefox不是开源的吗。哎呀我去。直接是浪费了时间。于是各种搜索
找到了firefox 56.0.2的下载版本。地址如下
http://releases.mozilla.org/pub/firefox/releases/56.0.2/source/firefox-56.0.2.source.tar.xz ;
下载解压如下图:

压缩文件1.5G解压后 n个G的大小,在这么多文件中找到hash也不是容易的事情。
于是下载了xsearch.exe (实际上EveryThing更好,但是木有下载)
看来上面的int __stdcall sub_1072C31E(int a1, int a2, _DWORD *a3)函数还是有用的
起码里面有 prefix_hi这个字符串,我们就按照这个来查询,如下图:

经过对查询到的每个文件进行快速感觉,最后发现了toolkit\components\places\SQLFunctions.cpp 文件,找到如下片段代码
////////////////////////////////////////////////////////////////////////////////
//// Hash Function
/* static */
nsresult
HashFunction::create(mozIStorageConnection *aDBConn)
{
RefPtr<HashFunction> function = new HashFunction();
return aDBConn->CreateFunction(
NS_LITERAL_CSTRING("hash"), -1, function
);
}
NS_IMPL_ISUPPORTS(
HashFunction,
mozIStorageFunction
)
NS_IMETHODIMP
HashFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
nsIVariant **_result)
{
// Must have non-null function arguments.
MOZ_ASSERT(aArguments);
// Fetch arguments. Use default values if they were omitted.
uint32_t numEntries;
nsresult rv = aArguments->GetNumEntries(&numEntries);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(numEntries >= 1 && numEntries <= 2, NS_ERROR_FAILURE);
nsString str;
aArguments->GetString(0, str);
nsAutoCString mode;
if (numEntries > 1) {
aArguments->GetUTF8String(1, mode);
}
RefPtr<nsVariant> result = new nsVariant();
if (mode.IsEmpty()) {
// URI-like strings (having a prefix before a colon), are handled specially,
// as a 48 bit hash, where first 16 bits are the prefix hash, while the
// other 32 are the string hash.
// The 16 bits have been decided based on the fact hashing all of the IANA
// known schemes, plus "places", does not generate collisions.
nsAString::const_iterator start, tip, end;
str.BeginReading(tip);
start = tip;
str.EndReading(end);
if (FindInReadable(NS_LITERAL_STRING(":"), tip, end)) {
const nsDependentSubstring& prefix = Substring(start, tip);
uint64_t prefixHash = static_cast<uint64_t>(HashString(prefix) & 0x0000FFFF);
// The second half of the url is more likely to be unique, so we add it.
uint32_t srcHash = HashString(str);
uint64_t hash = (prefixHash << 32) + srcHash;
result->SetAsInt64(hash);
} else {
uint32_t hash = HashString(str);
result->SetAsInt64(hash);
}
} else if (mode.Equals(NS_LITERAL_CSTRING("prefix_lo"))) {
// Keep only 16 bits.
uint64_t hash = static_cast<uint64_t>(HashString(str) & 0x0000FFFF) << 32;
result->SetAsInt64(hash);
} else if (mode.Equals(NS_LITERAL_CSTRING("prefix_hi"))) {
// Keep only 16 bits.
uint64_t hash = static_cast<uint64_t>(HashString(str) & 0x0000FFFF) << 32;
// Make this a prefix upper bound by filling the lowest 32 bits.
hash += 0xFFFFFFFF;
result->SetAsInt64(hash);
} else {
return NS_ERROR_FAILURE;
}
result.forget(_result);
return NS_OK;
}
} // namespace places
} // namespace mozilla 从中我们发现出了算法的整个结构 以及核心的HashString的算法,我们再对HashString进行搜索发现了mfbt\HashFunctions.h
代码如下:
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Utilities for hashing. */
/*
* This file exports functions for hashing data down to a 32-bit value,
* including:
*
* - HashString Hash a char* or char16_t/wchar_t* of known or unknown
* length.
*
* - HashBytes Hash a byte array of known length.
*
* - HashGeneric Hash one or more values. Currently, we support uint32_t,
* types which can be implicitly cast to uint32_t, data
* pointers, and function pointers.
*
* - AddToHash Add one or more values to the given hash. This supports the
* same list of types as HashGeneric.
*
*
* You can chain these functions together to hash complex objects. For example:
*
* class ComplexObject
* {
* char* mStr;
* uint32_t mUint1, mUint2;
* void (*mCallbackFn)();
*
* public:
* uint32_t hash()
* {
* uint32_t hash = HashString(mStr);
* hash = AddToHash(hash, mUint1, mUint2);
* return AddToHash(hash, mCallbackFn);
* }
* };
*
* If you want to hash an nsAString or nsACString, use the HashString functions
* in nsHashKeys.h.
*/
#ifndef mozilla_HashFunctions_h
#define mozilla_HashFunctions_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Char16.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Types.h"
#include <stdint.h>
#ifdef __cplusplus
namespace mozilla {
/**
* The golden ratio as a 32-bit fixed-point value.
*/
static const uint32_t kGoldenRatioU32 = 0x9E3779B9U;
inline uint32_t
RotateBitsLeft32(uint32_t aValue, uint8_t aBits)
{
MOZ_ASSERT(aBits < 32);
return (aValue << aBits) | (aValue >> (32 - aBits));
}
namespace detail {
inline uint32_t
AddU32ToHash(uint32_t aHash, uint32_t aValue)
{
/*
* This is the meat of all our hash routines. This hash function is not
* particularly sophisticated, but it seems to work well for our mostly
* plain-text inputs. Implementation notes follow.
*
* Our use of the golden ratio here is arbitrary; we could pick almost any
* number which:
*
* * is odd (because otherwise, all our hash values will be even)
*
* * has a reasonably-even mix of 1's and 0's (consider the extreme case
* where we multiply by 0x3 or 0xeffffff -- this will not produce good
* mixing across all bits of the hash).
*
* The rotation length of 5 is also arbitrary, although an odd number is again
* preferable so our hash explores the whole universe of possible rotations.
*
* Finally, we multiply by the golden ratio *after* xor'ing, not before.
* Otherwise, if |aHash| is 0 (as it often is for the beginning of a
* message), the expression
*
* (kGoldenRatioU32 * RotateBitsLeft(aHash, 5)) |xor| aValue
*
* evaluates to |aValue|.
*
* (Number-theoretic aside: Because any odd number |m| is relatively prime to
* our modulus (2^32), the list
*
* [x * m (mod 2^32) for 0 <= x < 2^32]
*
* has no duplicate elements. This means that multiplying by |m| does not
* cause us to skip any possible hash values.
*
* It's also nice if |m| has large-ish order mod 2^32 -- that is, if the
* smallest k such that m^k == 1 (mod 2^32) is large -- so we can safely
* multiply our hash value by |m| a few times without negating the
* multiplicative effect. Our golden ratio constant has order 2^29, which is
* more than enough for our purposes.)
*/
return kGoldenRatioU32 * (RotateBitsLeft32(aHash, 5) ^ aValue);
}
/**
* AddUintptrToHash takes sizeof(uintptr_t) as a template parameter.
*/
template<size_t PtrSize>
inline uint32_t
AddUintptrToHash(uint32_t aHash, uintptr_t aValue)
{
return AddU32ToHash(aHash, static_cast<uint32_t>(aValue));
}
template<>
inline uint32_t
AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue)
{
uint32_t v1 = static_cast<uint32_t>(aValue);
uint32_t v2 = static_cast<uint32_t>(static_cast<uint64_t>(aValue) >> 32);
return AddU32ToHash(AddU32ToHash(aHash, v1), v2);
}
} /* namespace detail */
/**
* AddToHash takes a hash and some values and returns a new hash based on the
* inputs.
*
* Currently, we support hashing uint32_t's, values which we can implicitly
* convert to uint32_t, data pointers, and function pointers.
*/
template<typename T,
bool TypeIsNotIntegral = !mozilla::IsIntegral<T>::value,
typename U = typename mozilla::EnableIf<TypeIsNotIntegral>::Type>
MOZ_MUST_USE inline uint32_t
AddToHash(uint32_t aHash, T aA)
{
/*
* Try to convert |A| to uint32_t implicitly. If this works, great. If not,
* we'll error out.
*/
return detail::AddU32ToHash(aHash, aA);
}
template<typename A>
MOZ_MUST_USE inline uint32_t
AddToHash(uint32_t aHash, A* aA)
{
/*
* You might think this function should just take a void*. But then we'd only
* catch data pointers and couldn't handle function pointers.
*/
static_assert(sizeof(aA) == sizeof(uintptr_t), "Strange pointer!");
return detail::AddUintptrToHash<sizeof(uintptr_t)>(aHash, uintptr_t(aA));
}
// We use AddUintptrToHash() for hashing all integral types. 8-byte integral types
// are treated the same as 64-bit pointers, and smaller integral types are first
// implicitly converted to 32 bits and then passed to AddUintptrToHash() to be hashed.
template<typename T,
typename U = typename mozilla::EnableIf<mozilla::IsIntegral<T>::value>::Type>
MOZ_MUST_USE inline uint32_t
AddToHash(uint32_t aHash, T aA)
{
return detail::AddUintptrToHash<sizeof(T)>(aHash, aA);
}
template<typename A, typename... Args>
MOZ_MUST_USE uint32_t
AddToHash(uint32_t aHash, A aArg, Args... aArgs)
{
return AddToHash(AddToHash(aHash, aArg), aArgs...);
}
/**
* The HashGeneric class of functions let you hash one or more values.
*
* If you want to hash together two values x and y, calling HashGeneric(x, y) is
* much better than calling AddToHash(x, y), because AddToHash(x, y) assumes
* that x has already been hashed.
*/
template<typename... Args>
MOZ_MUST_USE inline uint32_t
HashGeneric(Args... aArgs)
{
return AddToHash(0, aArgs...);
}
namespace detail {
template<typename T>
uint32_t
HashUntilZero(const T* aStr)
{
uint32_t hash = 0;
for (T c; (c = *aStr); aStr++) {
hash = AddToHash(hash, c);
}
return hash;
}
template<typename T>
uint32_t
HashKnownLength(const T* aStr, size_t aLength)
{
uint32_t hash = 0;
for (size_t i = 0; i < aLength; i++) {
hash = AddToHash(hash, aStr[i]);
}
return hash;
}
} /* namespace detail */
/**
* The HashString overloads below do just what you'd expect.
*
* If you have the string's length, you might as well call the overload which
* includes the length. It may be marginally faster.
*/
MOZ_MUST_USE inline uint32_t
HashString(const char* aStr)
{
return detail::HashUntilZero(reinterpret_cast<const unsigned char*>(aStr));
}
MOZ_MUST_USE inline uint32_t
HashString(const char* aStr, size_t aLength)
{
return detail::HashKnownLength(reinterpret_cast<const unsigned char*>(aStr), aLength);
}
MOZ_MUST_USE
inline uint32_t
HashString(const unsigned char* aStr, size_t aLength)
{
return detail::HashKnownLength(aStr, aLength);
}
MOZ_MUST_USE inline uint32_t
HashString(const char16_t* aStr)
{
return detail::HashUntilZero(aStr);
}
MOZ_MUST_USE inline uint32_t
HashString(const char16_t* aStr, size_t aLength)
{
return detail::HashKnownLength(aStr, aLength);
}
/*
* On Windows, wchar_t is not the same as char16_t, even though it's
* the same width!
*/
#ifdef WIN32
MOZ_MUST_USE inline uint32_t
HashString(const wchar_t* aStr)
{
return detail::HashUntilZero(aStr);
}
MOZ_MUST_USE inline uint32_t
HashString(const wchar_t* aStr, size_t aLength)
{
return detail::HashKnownLength(aStr, aLength);
}
#endif
/**
* Hash some number of bytes.
*
* This hash walks word-by-word, rather than byte-by-byte, so you won't get the
* same result out of HashBytes as you would out of HashString.
*/
MOZ_MUST_USE extern MFBT_API uint32_t
HashBytes(const void* bytes, size_t aLength);
/**
* A pseudorandom function mapping 32-bit integers to 32-bit integers.
*
* This is for when you're feeding private data (like pointer values or credit
* card numbers) to a non-crypto hash function (like HashBytes) and then using
* the hash code for something that untrusted parties could observe (like a JS
* Map). Plug in a HashCodeScrambler before that last step to avoid leaking the
* private data.
*
* By itself, this does not prevent hash-flooding DoS attacks, because an
* attacker can still generate many values with exactly equal hash codes by
* attacking the non-crypto hash function alone. Equal hash codes will, of
* course, still be equal however much you scramble them.
*
* The algorithm is SipHash-1-3. See <https://131002.net/siphash/>;.
*/
class HashCodeScrambler
{
struct SipHasher;
uint64_t mK0, mK1;
public:
/** Creates a new scrambler with the given 128-bit key. */
constexpr HashCodeScrambler(uint64_t aK0, uint64_t aK1) : mK0(aK0), mK1(aK1) {}
/**
* Scramble a hash code. Always produces the same result for the same
* combination of key and hash code.
*/
uint32_t scramble(uint32_t aHashCode) const
{
SipHasher hasher(mK0, mK1);
return uint32_t(hasher.sipHash(aHashCode));
}
private:
struct SipHasher
{
SipHasher(uint64_t aK0, uint64_t aK1)
{
// 1. Initialization.
mV0 = aK0 ^ UINT64_C(0x736f6d6570736575);
mV1 = aK1 ^ UINT64_C(0x646f72616e646f6d);
mV2 = aK0 ^ UINT64_C(0x6c7967656e657261);
mV3 = aK1 ^ UINT64_C(0x7465646279746573);
}
uint64_t sipHash(uint64_t aM)
{
// 2. Compression.
mV3 ^= aM;
sipRound();
mV0 ^= aM;
// 3. Finalization.
mV2 ^= 0xff;
for (int i = 0; i < 3; i++)
sipRound();
return mV0 ^ mV1 ^ mV2 ^ mV3;
}
void sipRound()
{
mV0 += mV1;
mV1 = RotateLeft(mV1, 13);
mV1 ^= mV0;
mV0 = RotateLeft(mV0, 32);
mV2 += mV3;
mV3 = RotateLeft(mV3, 16);
mV3 ^= mV2;
mV0 += mV3;
mV3 = RotateLeft(mV3, 21);
mV3 ^= mV0;
mV2 += mV1;
mV1 = RotateLeft(mV1, 17);
mV1 ^= mV2;
mV2 = RotateLeft(mV2, 32);
}
uint64_t mV0, mV1, mV2, mV3;
};
};
} /* namespace mozilla */
#endif /* __cplusplus */
#endif /* mozilla_HashFunctions_h */
好了,这下根据
firefox-56.0.2\toolkit\components\places\SQLFunctions.cpp
firefox-56.0.2\mfbt\HashFunctions.h
和IDA的逆向结果。最后写出大概如下代码(只写片段)
和IDA的逆向结果。最后写出大概如下代码(只写片段)
static const uint32_t kGoldenRatioU32 = 0x9E3779B9U;
uint32_t
RotateBitsLeft32(uint32_t aValue, uint8_t aBits)
{
。。。
}
uint32_t
AddU32ToHash(uint32_t aHash, uint32_t aValue)
{
。。。
}
uint32_t
HashUntilZero(const char* aStr)
{
。。。
}
uint32_t
HashKnownLength(const char* aStr, size_t aLength)
{
。。。
}
uint64_t ff_hash(char *s)
{
。。。
}
char *ff_fixup(char *s)
{
。。。
}
uint64_t page_url_hash(char *url)
{
return ff_hash(url);
}
uint64_t icon_url_hash(char *url)
{
return ff_hash(ff_fixup(url));
}
int main()
{
char url[1024];
printf("page url:\n");
gets(url);
printf("hash: %I64d\n", page_url_hash(url));
printf("icon url:\n");
gets(url);
printf("hash: %I64d\n", icon_url_hash(url));
return 0;
}
测试hash如下:
测试hash如下:

把这个结果和问题最开始一图的hash比较,那绝对的一模一样的。好了到这里核心问题算是解决了
出个结果图如下:

ok了冒泡完毕!还是那句话,这年头什么东西都越来越难了,不过只要静下心来,问题都可以去解决。
浏览器的各种加密来的更猛烈些吧。哥不怕你~
CopyRight @2018, Www.LiuLanQiCode.Com, Inc.All Rights Reserved. QQ:8560851 转载请标明来源,否则木有小jj