yoang 发表于 2023-10-1 21:25

已知解压函数求压缩函数

本帖最后由 yoang 于 2023-10-21 12:52 编辑

//说明
这个解密函数应该不算是一个加密,更像是一个解压算法,它把一个4k(0x1044)的大小字节文件,解压成了60k大小(0xffff)字符串,这个字符串的字符都是ascii字符。
所以下面这个解密函数可以看做是一个解压的算法函数,有没有大佬能看出下面这个算法是什么算法。或者有能力的大佬可以反向出他的压缩函数,或者给一个方向也可以。感谢大佬。

这个解压函数是用来解压一个大小为4k(0x1044)的文件,解压的结果是一个ascii的xml字符串,因为xml里有很多重复的标签,所以xml字符串经过压缩后,会变得很小。

它实际的用法是,把一个大的xml文件按顺序分成60k(0xffff)大小的段,然后逐段压缩成4k大小,然后按顺序写到1个文件里。下面这个函数就是读取1段压缩数据进行解压。

它的特点是不停的add(dl,dl),判断dl是否溢出,来获取解密的字符,可以从压缩字节里取,也可以从已解压好的字节里取。
dl一开始的值是0x80,add(dl,dl)后dl的值为0,如果dl值为0,直接把压缩字节输出到解压字节,然后dl取下一个压缩字节,继续解压。

//解密函数调用

      byte byte_al = 0;
      byte byte_dl = 0;

      uint encry_buffer_i = 0;          //ESI
      uint decry_buffer_i = 0;          //EDI

      byte[] encry_buffer;    //未解密字符缓存
      byte[] decry_buffer;    //已解密字符缓存
private void decry_run()
{
                //encry1文件保存了第1段压缩字节的数据,大小为4164字节
                using (FileStream fs = new FileStream("F:\\encry1", FileMode.Open))
                {
                  //用来缓存已解密字节
                  decry_buffer = new byte;

                  //用来缓存未解密字节
                  encry_buffer = new byte;

                  fs.Read(encry_buffer, 0, 4164)

                        flag_CF = 1;
                        flag_ZF = 0;

                        byte_al = 0x8;
                        byte_dl = xl_mov(0x80);

                        encry_buffer_i = 0;
                        decry_buffer_i = 0;

                        //解密路线0
                        direct_loc_140C059();
                   }

}



//----------------------------------------下面是解密函数主体内容



         

      

下面是encry1,第1段压缩字节文件,大小为4164字节:
5F 1E 74 E5 9D CE C7 74 D8 F5 67 74 B8 D5 1F 74 63 FF 2F 1D C0 DD A7 D1 29 F7 67 74 9B 5B 96 F6 9F BF 4A FD 6B D1 98 D7 67 74 BB 53 F0 56 7D 74 8F 7C BD 9D 44 76 7B 74 B5 9F 96 47 74 D8 57 FE 9D F4 15 6E F3 A9 82 EF 4B E2 E0 EA AF 4F A3 0C AA D3 8E 0C EF 4B 3A 66 FD 2B A3 AA BA 96 A6 6F FB D6 ED 93 AF BF 5E E3 12 AB 96 F8 36 EA B9 2C 4B EA B4 E2 99 EE 92 A2 B4 E9 2A E6 65 E9 3A A7 16 EB F5 F3 5E AE 8F 74 72 AE 3B A1 CF 74 B1 EA 9A E4 55 CD EB 53 4E 66 A8 BB BA BD 61 BE 2F A7 02 A9 3A A7 23 EE F5 E2 AC EF D6 3A B8 FE 4E A8 BB EE F5 9B B9 E4 BE 2E 93 E6 00


下面是已解压的内容,大小为60k,这里只放前面一部分 (附件好像不能传图片以外的文件):
Name='


小雨网络 发表于 2023-10-2 17:45

这个解压函数是一个解压算法,具体的算法逻辑如下:

初始化标志位和变量。
进入解密函数的主体内容,循环执行以下步骤:
a. 调用cur_encry_byte_output()函数,处理当前加密字节。
b. 将加密缓存中的一个字节放入al寄存器,并将al的值存入解密缓存中。
c. 调用cur_decry_byte_output()函数,处理当前解密字节。
d. 将解密缓存指针和加密缓存指针分别加1。
e. 设置ebx寄存器的值为2。
f. 跳转到解密函数的线路1,直到返回到loc_140C059。
g. 判断函数返回值,如果返回值为loc_140C059,继续下一次循环;如果返回值为loc_end,结束循环;如果返回值为其他值,显示错误信息。
返回解密函数的调用位置。

根据以上分析,这个解密函数的算法逻辑是通过循环将加密缓存中的每一个字节解密,并将解密结果存入解密缓存中。具体的解密过程包括对加密字节进行处理、将解密结果存入解密缓存、处理解密字节、更新解密缓存指针、设置ebx寄存器的值等步骤。
根据解密函数的逻辑,可以推测出它的压缩函数的逻辑大致如下:

初始化标志位和变量。
进入压缩函数的主体内容,循环执行以下步骤:
a. 对输入数据进行处理,得到一个字节。
b. 将该字节按照压缩算法的逻辑进行处理,得到一个加密字节。
c. 将加密字节存入加密缓存中。
d. 更新加密缓存指针。
e. 继续处理下一个输入数据,直到处理完所有数据。
返回加密缓存。

由于具体的压缩算法逻辑无法直接从解密函数的代码中推导出来,因此需要进一步分析压缩函数的调用位置和参数,以及与解密函数之间的关系,才能确定压缩算法的具体逻辑。

侃遍天下无二人 发表于 2023-10-21 14:20

你这段代码是从IDA的伪码里弄出来的吧,先还原成能开发环境中调试通过并正确运行的代码再考虑压缩函数的事

yoang 发表于 2023-11-24 06:39

侃遍天下无二人 发表于 2023-10-21 14:20
你这段代码是从IDA的伪码里弄出来的吧,先还原成能开发环境中调试通过并正确运行的代码再考虑压缩函数的事

感谢回复,不是伪代码,是从IDA提取的解压函数的汇编代码,我把解压函数的汇编代码逻辑用C#还原出来了,可以进行正常解压。
本来想问下是否是某个知名的压缩算法,找对应的解压算法就行了。找不到所以又花了半个月根据解压函数一点点反推了一个压缩函数出来,也弄明白了整个解压函数的原理,虽然没有它原来那么完美,不过每压缩60000个字节会比它原来大80个字节左右,先这样用了。
整个压缩的方法就是不停往前匹配,匹配到重复的就记录下,对重复字节多的文件,压缩率比较高60000个字节大概能压缩到4000个字节左右
页: [1]
查看完整版本: 已知解压函数求压缩函数