首页
社区
课程
招聘
[原创]一道很难的有关算法的测试题,写逆算法
发表于: 2007-7-28 14:16 16026

[原创]一道很难的有关算法的测试题,写逆算法

2007-7-28 14:16
16026

一道很难的有关算法的测试题,写逆算法

最近在学习压缩算法,刚学懂了一个压缩算法,把它加以改造,做成了一道测试题.
这道题很难,这个算法很巧.如果不知道答案,我都没有把握能做出来.
如果你自信算法方面很强,可以试一试.如果你做不出来,又想知道答案,联系我.
以下已经给出了完整的 Decode 代码,Encode 代码有几处空,填入代码,使算法工作.

这个算法可以广泛地应用于注册机,网络传输等方面.

如果你做出来了,我愿高薪聘你

#include <Windows.h>
#include <stdio.h>

class CBitEncoder
{
  PBYTE m_pbuf;
  UINT m_len;

  UINT Prob;
  UINT _cacheSize;
  BYTE _cache;

  UINT64 Low;
  UINT uiSom;

  void WriteByte(BYTE b)  {          m_pbuf[m_len++] = b;  }
  void Init()
  {
    Prob = (1 << 10);
    Low = 0;
    uiSom = 0xFFFFFFFF;
    _cacheSize = 0;
    _cache = 0;
  }
  void ShiftLow()
  {
    此处空13行代码;
  }
public:
  void SetOutputBufPtr(PBYTE buf)
  {
    Init();
    m_pbuf = buf;
    m_len = 0;
  }
  int GetLength()  {    return m_len;  }

  void FlushData()
  {
    此处空2行代码;
  }

  void bEncode(UINT symbol)
  {
    此处空17行代码;
  }
};
//---------------以上是 Encoder 以下是 Decoder

class CBitDecoder
{
  PBYTE m_psrc;
  int m_srclen;

  UINT uiSom;
  UINT uiAny;
  UINT Prob;

  BYTE ReadByte()
  {
    m_srclen--;
    return *m_psrc++;
  }
  void Init()
  {
    Prob = (1 << 10);
    uiAny = 0;
    uiSom = 0xFFFFFFFF;
    for(int i = 0; i < 4; i++)
      uiAny = (uiAny << 8) | this->ReadByte();
  }
public:
  void SetSrcBuf(PBYTE psrc, int srclen)
  {
    m_psrc = psrc;
    m_srclen = srclen;
    Init();
  }
  int GetRemainByte()  {    return m_srclen;  }
  
  bool bDecode()
  {
    bool b;
    UINT u = (this->uiSom >> 11) * this->Prob;
    if (this->uiAny < u)
    {
      this->uiSom = u;
      this->Prob += ((1 << 11) - this->Prob) >> 5;
      b = false;
    }
    else
    {
      this->uiSom -= u;
      this->uiAny -= u;
      this->Prob -= (this->Prob) >> 5;
      b = true;
    }
    if (this->uiSom < (1 << 24))
    {
      this->uiAny = (this->uiAny << 8) | this->ReadByte();
      this->uiSom <<= 8;
    }
    return b;
  }
};

int Test_Encode(PBYTE psrc, int srclen, PBYTE buf)
{
  CBitEncoder bitEncoder;
  bitEncoder.SetOutputBufPtr(buf);

  for (int i=0;i<srclen;i++)
  {
    BYTE b = psrc[i];
    for (int j=0;j<8;j++)
    {
      bitEncoder.bEncode((b>>j) & 1);
    }
  }
  bitEncoder.FlushData();

  return bitEncoder.GetLength();
}

int Test_Decode(PBYTE psrc, int srclen, PBYTE buf)
{
  CBitDecoder bitDecoder;
  bitDecoder.SetSrcBuf(psrc, srclen);

  int totallen = 0;
  for (;;)
  {
    BYTE b = 0;
    for (int i=0;i<8;i++)
    {
      b += (bitDecoder.bDecode() << i);
      if (bitDecoder.GetRemainByte() < 0)
        return totallen;
    }
    *buf++ = b;
    totallen++;
  }
  return totallen;
}

void main()
{
  char* psrc = "exam by LiuTaoTao 20070728";
  int srclen = strlen(psrc);
  BYTE buf[3000];
  int len = Test_Encode((PBYTE)psrc, srclen, buf);
  printf("Srclen = %d Encode len = %d \n", srclen, len);

  BYTE outbuf[3000];
  int len2 = Test_Decode(buf, len, outbuf);
  printf("Decode len from %d to %d \n", len, len2);
  if (len2 >= srclen && !memcmp(psrc, outbuf, srclen))  
    printf("OK\n");  
  else
    printf("Error\n");
}
// 这种压缩算法,代码简单,速度快.最差的情况,是增长4个字节
// 还有一个缺点,就是不能很有效地判断是否已经解码结束,有时候会多解几个字节出来


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (36)
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
2
难道是bit group压缩?
感觉没什么实际价值,弄个huffman tree都……
2007-7-28 15:36
0
雪    币: 193
活跃值: (1409)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
學習編程風格
2007-7-28 15:40
0
雪    币: 2134
活跃值: (14)
能力值: (RANK:170 )
在线值:
发帖
回帖
粉丝
4
还准备沙发的呢,学习........
2007-7-28 15:42
0
雪    币: 437
活跃值: (273)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
5
   在学校没怎么学算法 都在反汇编  搞底层的
2007-7-28 17:00
0
雪    币: 234
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
6
好东西,等我回家改写成C#...
2007-7-28 17:36
0
雪    币: 228
活跃值: (119)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
既然LTT都说难,那就是肯定难,偶毛子是做不出来的了,
期待高手应招!
2007-7-28 22:08
0
雪    币: 468
活跃值: (340)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
8
答错了,不是 bit group.
每个算法都有自己存在的理由.huffman 是好,但太复杂,需要建huffman树,还要保存huffman树.
这个算法简单,速度快,一边进,一边出,是一种流式的压缩.
而且有一定难度,根据decode不太容易写出encode,加到注册算法中,破解者要先解了
这道题才能做出 keygen
2007-7-29 09:29
0
雪    币: 1969
活跃值: (46)
能力值: (RANK:550 )
在线值:
发帖
回帖
粉丝
9
学习。。。。。。
2007-7-29 10:31
0
雪    币: 8209
活跃值: (4518)
能力值: ( LV15,RANK:2473 )
在线值:
发帖
回帖
粉丝
10
压缩算法一点没研究过,所以先顺便找一篇压缩的文章学习一下基本原理:《聪明的以色列人(上):LZ77》
虽然和本题关系不大,也算概念入门了
上传的附件:
2007-7-29 21:45
0
雪    币: 8209
活跃值: (4518)
能力值: ( LV15,RANK:2473 )
在线值:
发帖
回帖
粉丝
11
看看谁能把下面的内嵌汇编转成C语言的:

int Test_Encode(PBYTE psrc, int srclen, PBYTE buf)
{
        BYTE    _cache;
        DWORD   Low_l;
        DWORD   Low_h;
        DWORD   uiSom;
        int     i;
        int     j;
        BYTE    b;

        __asm
        {
            xor     edi, edi
            xor     edx, edx
            xor     esi, esi
            mov     ebx, 400h
            mov     Low_l, edx
            mov     Low_h, edx
            mov     uiSom, 0FFFFFFFFh
            mov     _cache, dl
            mov     i, edx
            cmp     srclen, 0
            jle     loc_01
        loc_12:     
            mov     eax, psrc
            mov     ecx, i
            mov     j, 0
            mov     dl, [ecx+eax]
            mov     b, dl
        loc_11:     
            mov     al, b
            mov     cl, byte ptr j
            mov     edx, uiSom
            shr     al, cl
            shr     edx, 0Bh
            imul    edx, ebx
            test    al, 1
            jnz     loc_02
            mov     ecx, 800h
            mov     uiSom, edx
            sub     ecx, ebx
            shr     ecx, 5
            add     ebx, ecx
            jmp     loc_03
        loc_02:     
            add     Low_l, edx
            adc     Low_h, 0
            sub     uiSom, edx
            mov     edx, ebx
            shr     edx, 5
            sub     ebx, edx
        loc_03:     
            cmp     uiSom, 1000000h
            jnb     loc_04
            shl     uiSom, 8
            cmp     Low_l, 0FF000000h
            jb      loc_05
            cmp     Low_h, 0
            jz      loc_06
        loc_05:     
            mov     cl, _cache
            test    esi, esi
            jz      loc_07
            mov     al, byte ptr Low_h
        loc_08:     
            mov     dl, al
            add     dl, cl
            mov     ecx, buf
            mov     [edi+ecx], dl
            inc     edi
            or      cl, 0FFh
            dec     esi
            jnz     loc_08
        loc_07:     
            mov     eax, Low_l
            shr     eax, 18h
            mov     _cache, al
            jmp     loc_09
        loc_06:     
            mov     al, _cache
        loc_09:     
            shl     Low_l, 8
            mov     Low_h, 0
            inc     esi
            jmp     loc_10
        loc_04:
            mov     al, _cache
        loc_10:
            inc     j
            cmp     j, 8
            jl      loc_11
            mov     edx, srclen
            inc     i
            cmp     i, edx
            jl      loc_12
        loc_01:     
            mov     srclen, 5
        loc_17:     
            mov     edx, Low_l
            cmp     edx, 0FF000000h
            jb      loc_13
            cmp     Low_h, 0
            jz      loc_14
        loc_13:     
            test    esi, esi
            jz      loc_15
            mov     cl, byte ptr Low_h
        loc_16:     
            mov     bl, cl
            add     bl, al
            mov     eax, buf
            mov     [edi+eax], bl
            inc     edi
            or      al, 0FFh
            dec     esi
            jnz     loc_16
        loc_15:     
            mov     eax, edx
            shr     eax, 18h
        loc_14:     
            inc     esi
            shl     edx, 8
            mov     Low_l, edx
            mov     Low_h, 0
            dec     srclen
            jnz     loc_17
            mov     i, edi
        }

        return i;
}
2007-7-30 22:05
0
雪    币: 468
活跃值: (340)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
12
ccfer 我不知道你是不是已经把 encode 写出来了
这个代码短小精悍,Test_Decode 和 Test_Encode 编译后都是一个干净的函数,
没有 call 出,且都很短小.这么简练的代码,就这么难逆,不可多得
2007-7-31 08:33
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
如果ccfer没有把encode写出来了, 那么他上传的test.exe怎么来的呢
额比较关心楼主愿意用多高的薪聘ccfer
2007-7-31 08:47
0
雪    币: 468
活跃值: (340)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
14
ccfer发了两贴,一贴是....与本题关系不大...
后面跟了个附件test.rar

二贴是谁能把一段ASM写成C++

我怎么都不明白他是解的我的题.如果他解出来了,帖子应该这么写:
我解出来了!这是我的代码(见附件)

发贴太隐讳了
2007-7-31 09:18
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
先声明我不是ccfer的马甲,我只是他的粉丝
ccfer这么做可能是这样的道理 "零知识证明"
就是他在能请明自己完成的情况下,同时不把答案直接告诉其他人
试想如果ccfer直接贴出了c++代码,那么对其他想做题目的人是不公平的
2007-7-31 09:24
0
雪    币: 8209
活跃值: (4518)
能力值: ( LV15,RANK:2473 )
在线值:
发帖
回帖
粉丝
16
按照楼主的程序风格FlushData()里面应该是4行吧
2007-7-31 09:24
0
雪    币: 468
活跃值: (340)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
17
我测试了 ccfer 的 Test_Encode ,恭喜你,答对了!
强啊!这么难的题,都被解了,怪不得卫星都上天了呢!
2007-7-31 09:36
0
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
18
牛           B
2007-7-31 09:53
0
雪    币: 2134
活跃值: (14)
能力值: (RANK:170 )
在线值:
发帖
回帖
粉丝
19
心情比较差,论文看不进
昨天看了下代码,这儿做个总结
Decode主要就是uiAny为读入数据,
prob作为调整数据,每次都在1024左右
然后按照u, uiSom解码,如果uiAny落在[0-u)之间,解码0,如果uiAny落在[u-uiSom]之间,就解码为1
对uiSom,prob,u做调整,
调整在一个8位字节中,大概主要是对0xffffffff-0x0之间,当然,具体有小变化,由prob调整,每次u大概为uiSom的一半左右,看前次输出的值为0还是为1,调整prob,如果输出为0,每次prob 变大一点,不到(1/32),否则,每次prob 变小,减少1/32,

调整大概就是对0xffffffff-0x0之间
0xffffffff/2,输出1,小于,输出0,------------------第一位
0xffffffff/2,0xffffffff/4 输出1,小于,输出0,-----第二位
0xffffffff/4,0xffffffff/8 输出1,小于,输出0,-----第三位
。。。。。。。。。。

注意上面不是一定的,是大概情况而以
以上所说的就是解码这一块

我想了下,如果要编码的话,应该要构造出符合上述条件的uiAny,但是从解码过程可以看到,
每次解码大概8位以后,是需要读入下一个字节的,然后uiAny左移8位,而每次比较的时候是uiAny,每次为输出为1时需要减的也是uiAny,所以uiAny是后向相关的,也就是说,每次对uiAny减了一次后,对后面的解码有影响。

所以在编码的时候如何考虑这个后向影响呢?
首先,编码的时候,我想到的结构和解码一样,
u,uiSom,prob都没有变化

u=......

if(symble ==0)
{
}else
{
}

不过对Low做变化的时候需要ShiftLow,感觉要在这块处理后向相关,应该是每次逆置,
------------此处没有搞通----------达人不要谦虚阿,多放上来:))
FlushData是要对Low中残余的数据输出........:)
2007-7-31 10:16
0
雪    币: 2134
活跃值: (14)
能力值: (RANK:170 )
在线值:
发帖
回帖
粉丝
20
给出一个代码;)
    void bEncode(UINT symbol)
    {	
        UINT	u = (this->uiSom >> 11) * this->Prob;   	// 变小,大概1/2左右,看Prob是大于0x400还是小于0x400
        
        if(symbol == 0){// uiAny始终比uiSom小
            
            this->uiSom = u;  								
            this->Prob += ((1 << 11) - this->Prob) >> 5;	
        }
        else{    // uiAny >= u
            
            //uiAny -= u; 		
            this->Low += u; 	
            this->uiSom -= u; 	
            this->Prob -= (this->Prob) >> 5;// prob 变小,减少1/32,如果一直输入一,则prob会变得很小-0x1f
        }
        
        if(this->uiSom < (1 << 24)){
        	//如果最高位8位全0,写入一个字节,同时左移8位
            this->ShiftLow();
            this->uiSom <<= 8;
        }
    }

    void ShiftLow()
    {	
        if(_cacheSize)
        {
            if(_cache == 0xff && (Low>>32 & 0x000000ff) )  
            {
                int i;
                for (i=1; m_pbuf[m_len-i]==0xff&&(m_len-i)>=0;i++)	
                    m_pbuf[m_len-i]=0;
                if((m_len-i)>=0)m_pbuf[m_len-i]++;
                else
                {
                    for(i=m_len++; i>=0; i--)
                        m_pbuf[i]=m_pbuf[i-1];
                    m_pbuf[0]=1;
                }
            }
            WriteByte(((Low>>32 & 0x000000ff) + _cache));	
            _cacheSize--;
        }
        _cache = ((Low >>24) & 0x000000ff);	 
        _cacheSize++; 
        Low <<= 8;  
        Low &= 0xffffffff;
    }

    void FlushData()
    {
        for(int i = 0; i<_cacheSize+sizeof(DWORD)/sizeof(BYTE);i++)
            ShiftLow();
    }
2007-8-1 08:11
0
雪    币: 398
活跃值: (343)
能力值: (RANK:650 )
在线值:
发帖
回帖
粉丝
21
又一个高薪人才
2007-8-1 08:34
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
22
今天我进步了,因为我碰到了
2007-8-1 10:57
0
雪    币: 228
活跃值: (119)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
23
牛X的不行,LTT的钱箱串钱的线都要烂掉了,哈哈,高薪请过去,解大峡之愁
2007-8-1 12:38
0
雪    币: 468
活跃值: (340)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
24
恭喜 AKer 也做对了! 大家太厉害了
长江后浪推前浪,一浪更比一浪浪
2007-8-1 16:58
0
雪    币: 12
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
AKer 的不对吧,试了一下代码出错。
2007-8-1 17:04
0
游客
登录 | 注册 方可回帖
返回
//