6767 发表于 2017-8-22 07:22

【160 crackme 之52 】 注册码算法分析

本帖最后由 6767 于 2017-12-24 21:18 编辑

160CM 里面的三个5星难度之一
## 052.esgis.1

`UPX 0.89 - 3.xx -> Markus & Laszlo ver. [ 0.76 ] <- from file.`
A classic viusal C++ programe, compiled at 1998.
### Headers
长文预警
本文大概有三千个字


先上图;

!(SuccessfulCracked.png)


使用linxue的脱壳机去掉packer,或者使用通用oep大法,upx主要是压缩没有加密,反正也不难。
追踪 引用字符串找到函数结点;

```c
int __thiscall sub_401C20(void *this) {
    void *_this; // ebp@1
    unsigned int len_plus1; // kr20_4@1
    char *v3; // edi@1
    int v4; // eax@1
    int Ntimes64; // esi@3
    int ii; // edi@3
    int result; // eax@6
    signed int j; // esi@7
    unsigned int *guessPtr; // edi@7
    signed int i; // eax@9
    DWORD Type; // @1
    DWORD cbData; // @1
    HKEY phkResult; // @1
    int guessHex; // @5
    char v15; // @5
    char v16; // @5
    char v17; // @5
    int C0_FF_0; // @1
    int v19; // @3
    char userString; // @1
    BYTE tmp; // @1
    CHAR guessString; // @1

    _this = this;
    memset(userString, 0, sizeof(userString));
    memset(&guessString, 0, 0x1F4u);
    memset(&tmp, 0, 0x1F4u);
    getStrFromTextBox(this + 92, userString, 100);
    getStrFromTextBox(_this + 172, &guessString, 100);
    strcpy(&tmp, userString);
    _strrev(&tmp);                              // input1 reversed
    strcat(userString, &tmp);                     // normal+reversed str
    RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", &phkResult);
    Type = 1;
    cbData = 256;
    RegQueryValueExA(phkResult, "ProductID", 0, &Type, &tmp, &cbData);
    Type = 1;
    strcat(userString, &tmp);
    cbData = 256;
    RegQueryValueExA(phkResult, "RegisteredOwner", 0, &Type, &tmp, &cbData);
    strcat(userString, &tmp);                     // 1234_4321_4321_4321
    len_plus1 = strlen(userString) + 1;
    setConst_4016E0(C0_FF_0);
    memset(&userString, 0, 76u);
    v3 = &userString;
    *v3 = 0;
    v3 = 0;
    v4 = 64 - (len_plus1 & 0x3F);
    userString = 0x80u;
    if ( v4 <= 7 )
      v4 += 64;
    Ntimes64 = v4 + len_plus1;
    ii = 0;
    for ( *(&v19 + v4 + len_plus1) = 8 * strlen(userString); ii < Ntimes64; ii += 64 )
      MD5like_401700(&userString, C0_FF_0);       // MD5 like
    //
    C0_FF_0 = LOWORD(C0_FF_0);
    if ( sscanf(&guessString, "%lx%lx%lx%lx", &guessHex, &v15, &v16, &v17) == 4 ) { // guess text like :'0x12341234 0x12341234 0x12341234 0x12341234'
      j = 0;
      guessPtr = &guessHex;
      do {
            rolN_401B90(guessPtr, 0xBADC0DE / (j++ + 0x50));
            ++guessPtr;
      } while ( j < 3 );
      i = 0;
      while ( *(&guessHex + i * 4) == C0_FF_0 ) {
            ++i;
            if ( i >= 4 )
                return msgbox_4100A8("... Man, you're good enough to join CORE! ...", "Welcome", 0x40u);
      }
      result = msgbox_4100A8("... Better luck next time ...", "Failed", 0x30u);
    } else {
      result = msgbox_4100A8("... Hmmm, you don't even pass the first threshold ...", "Failed", 0x30u);
    }
    return result;
}
```
主要函数就在这个block里。
内存地址:0x19ed24
inputtext1.会操作3次得到一个4倍长度的strings1(Win10注册表是空,直接复制3次),inputtext2以`%lx`的方式读入4个,然后调用sub_401B90循环移位N次得到一个16bytes的字符串,与strings1 的类似MD5摘要结果进行比较。
```
input1->(like MD5 digest)——┐
                        cmp---(Y/N)
input2->(ROL+strange+1)___」
```
### MD5 like func
使用PEid的Krypto 插件检查算法会发现有且仅有md5算法,
地址块 :`dword_41B0B0 `;

所有的常数(F G H I)里面的都是对的,包括`UPX0:setConst_4016E0`函数 sets initial magic number;
但是,怎么看这个函数都不是正常的标准md5,也没有动力去分析一个修改过的md5;
考虑到在`UPX0:00401E56`还and了一个0xffff,表明直接爆破md5是不可能的了;
不过可以在内存地址里得到摘要值;

- Note Here: 注意啦,已经有更好的md5分析了 https://www.52pojie.cn/thread-677861-1-1.html

对应于 "0000"的输入,摘要值是
```
0019ED34|BB A2 00 00 B8 2E 9A A3|42 25 88 E8 70 B8 C4 9D|........B%..p...
```
这16bytes数据;

### ROL strange array
这个函数是最有意思的函数;开始的时候发现它每次循环修改2 int,
`c,c,c`,
循环3次刚刚好全部的16bytes

查看反汇编伪代码
```c
char *__cdecl rolN_401B90(unsigned int *ptr, int const1)
{
char *result; // eax@1
int cnt; // ebx@1
unsigned int Lsi; // esi@1
unsigned int Hdi; // edi@1
unsigned __int64 tt0; // rax@2
int t1; // esi@2
int t2; // edi@2
unsigned __int64 tt; // rax@2

result = ptr;
cnt = const1;
Lsi = *ptr;
Hdi = ptr;
if ( const1 )
{
    do
    {
      tt0 = 2 * __PAIR__(Hdi, Lsi);
      LODWORD(tt0) = ((2 * Lsi) | (Hdi >> 31)) & 4;
      t1 = tt0 | (Hdi >> 31);
      t2 = HIDWORD(tt0);
      tt = tt0 << 11;
      LODWORD(tt) = t1 & 0x2000 ^ tt;
      tt <<= 18;
      LODWORD(tt) = t1 & 0x80000000 ^ tt;
      tt *= 2i64;
      Lsi = tt ^ t1;
      Hdi = HIDWORD(tt) ^ t2;
      --cnt;//IDA监控点
    }
    while ( cnt );
    result = ptr;
}
*result = Lsi;
*(result + 1) = Hdi;
return result;
}
```
不好意思,研究了好久发现,这个代码是错误的,但是只有试过才大概了解到一大堆位运算在干嘛;
在这个地方卡了好久,花时间修改导出的C代码,发现是错误的计算结果;

经过汇编跟踪比较,发现伪代码错误,放弃;

用IDA dump脚本监控前几百次运行是这样的:

```c
   ebx,         esi,   edi,
0,00255F35,00000001,00000002,0000000200000001
1,00255F35,00000002,00000004,0000000400000002
2,00255F34,00000004,00000009,0000000900000004*
3,00255F33,00000008,00000012,0000001200000008
4,00255F32,00000010,00000024,0000002400000010
5,00255F31,00000020,00000048,0000004800000020
6,00255F30,00000040,00000090,0000009000000040
7,00255F2F,00000080,00000120,0000012000000080
8,00255F2E,00000100,00000240,0000024000000100
9,00255F2D,00000200,00000480,0000048000000200
A,00255F2C,00000400,00000900,0000090000000400
B,00255F2B,00000800,00001200,0000120000000800
C,00255F2A,00001000,00002400,0000240000001000
D,00255F29,00002000,00004801,0000480100002000*
E,00255F28,00004000,00009002,0000900200004000
```

#### Try Brute force
这里走歪了;

这个函数 接受 4 uint,运行后和md5like 的摘要比较,得到是否正确;
前面说到了,直接用导出的fake C code是不能用的,于是我们想要爆破的话,直接用汇编代码来运行就好了嘛;

这里主要写内联汇编,把rolN_401B90 函数的汇编代码提取出来,在vs2015里改写接口部分,

```c
__declspec(naked)
char* __cdecl rolN_401B90(unsigned int *Cptr, int Cconst1) {

      //checked match original funcs
#define ptr 4
#define const1 8

      __asm {
                mov   eax,
                        push    ebx
                        mov   ebx,
                        push    esi
                        mov   esi,
                        push    edi
            ...MORE...
            RETZERO:; CODE XREF : __allshl + 3j
                        xor   eax, eax
                        xor   edx, edx
                        retn
      }
#undef ptr
#undef const1
}
```
运行了一个测试,发现是正确的;
于是写了一个爆破Generator function 来初始化输入值,每10000次打个log;
结果是,原始汇编代码运行1W次时间,4~5minutes,

如果要爆破完16bytes,需要集群了,emm.....
有没有土豪赞助我一车GTX1080和i7 7700K 吗

直接爆破不行,就需要分析这个汇编blocks在干嘛,这里现在看来是**最最重要的**;

前面调试可以看到全部是位运行,既然是数学,这里使用符号传递来尝试分析;事实证明这个方法是正确的。
```assembly
; char* __declspec(naked) __cdecl rolN_401B90(unsigned int *ptr, int const1)
rolN_401B90   proc near               ; CODE XREF: sub_401C20+284p
;ptr             = dword ptr4
;const1          = dword ptr8
               mov   eax,
               push    ebx
               mov   ebx, ;cnt;
               
               push    esi
               mov   esi, ;c
               push    edi
               mov   edi, ;c
               
               test    ebx, ebx
               jbe   short loc_401C15
               push    ebp

loop1:                           ; CODE XREF: rolN_401B90+7Ej
               mov   ebp, edi
               mov   ecx, 1   ;ecx=1;
               shr   ebp, 1Fh
               mov   , ebp;get c.bit31;
               mov   eax, esi
               mov   edx, edi
               xor   ebp, ebp       ;ebp=0
               call    __allshl;            edx,eax <<1
               ;eax=c<<1
               ;edx=c<<1|c>>31;
               mov   ecx, ;ecx=c>>31
               or      ebp, edx       ; mov ebp,edx;
                                        ;ebp=c<<1 | c>>31;
               or      ecx, eax       ;ecx=c>>31|(c<<1);
               xor   edx, edx       ;edx=0;
               mov   esi, ecx       ;esi=c>>31|(c<<1);
               mov   ecx, 11      ;ecx=11
               mov   eax, esi       ;eax=c>>31|(c<<1);
               mov   edi, ebp       ;edi=c<<1 | c>>31 ;
               and   eax, 4         ;eax=(c>>31|(c<<1)) & 4;
               call    __allshl
               ;eax=((c.bit31|(c<<1)) & 4)<<11
               ;eax=((c>>31|(c<<1)) & 4)<<11
               ;eax=((c<<1) & 4)<<11
               ;eax=( c&2 ) <<12
               ;edx=0
               mov   ecx, esi       ;ecx=c>>31|(c<<1)
               xor   ebp, ebp       ;ebp=0
               and   ecx, 2000h   ;ecx=(c>>31|(c<<1)) & 0x2000
                                        ;ecx=(c<<1) & 0x2000
               xor   edx, ebp       ;NOP;ebp==0
               xor   eax, ecx       ;eax=(((c<<1) & 4)<<11) ^ (c<<1 & 0x2000)
                                        ;eax=(    ( c&2 ) <<12) ^ (c<<1 & 0x2000)
               mov   ecx, 12h       ;ecx=18;
               call    __allshl
               ;eax=( (( c&2 ) <<12) ^ (c<<1 & 0x2000)) <<18
               ;edx=( (( c&2 ) <<12) ^ (c<<1 & 0x2000)) >>14   Always edx==0
               ;
               mov   ecx, esi       ;ecx=c>>31|(c<<1);
               xor   edx, ebp       ;NOP,ebp==0;
               and   ecx, 80000000h ;ecx=c.bit31|(c<<1) & 0x8000_0000;
                                        ;ecx=(c<<1) & 0x8000_0000;
               xor   eax, ecx      
               ;eax=(((( c&2 ) <<12) ^ (c<<1 & 0x2000))<<18 )^( (c<<1) & 0x8000_0000 )
               mov   ecx, 1         ;ecx=1
               call    __allshl
               ;eax=((((( c&2 ) <<12) ^ (c<<1 & 0x2000))<<18 )^( (c<<1) & 0x8000_0000 ))<<1;
               ;edx=(((( c&2 ) <<12) ^ (c<<1 & 0x2000)) >> 14)<<1 |( (((( c&2 ) <<12) ^ (c<<1 & 0x2000))<<18 )^( (c<<1) & 0x8000_0000 ) )>>31
               

               xor   esi, eax
                ;c=(c>>31|(c<<1))   ^(   ((((( c&2 ) <<12) ^ (c<<1 & 0x2000))<<18 )^( (c<<1) & 0x8000_0000 ))<<1)
                ;                           ^ ((c.bit1<<31 ^ c.bit12<<31 ^ c.bit30<<31 )<<1)
                ;c=(c>>31|(c<<1)) ^ 0
                ;c= c>>31|(c<<1)
               
               xor   edi, edx
                ;c=(c<<1 | c>>31)   ^( (((( c&2 ) <<12) ^ (c<<1 & 0x2000)) >> 14)<<1 |( (((( c&2 ) <<12) ^ (c<<1 & 0x2000))<<18 )^( (c<<1) & 0x8000_0000 ) )>>31 )
                ;                               (      c.bit1<<13^c.bit12<<13    )>>14<<1
                ;c=(c<<1 | c>>31)   ^(      0                                              |(c.bit1<<31 ^ c.bit12<<31 ^ c.bit30<<31 )>>31)
                ;c=(c<<1 | c>>31)   ^(c.bit1 ^ c.bit12 ^ c.bit30 )
                ;c=(c<<1 | c>>31)   ^(c>>1 ^c>>12 ^c>>30)&1
                ;c= c<<1 ^ (c>>31 ^c>>1 ^c>>12 ^c>>30)&1
               dec   ebx
               jnz   short loop1
               mov   eax,
               pop   ebp

loc_401C15:                           ; CODE XREF: rolN_401B90+12j
               mov   , esi
               mov   , edi
               pop   edi
               pop   esi
               pop   ebx
               retn
                endp
               
__allshl      proc near               ; CODE XREF: rolN_401B90+29p
                                       ; rolN_401B90+46p ...
                ; cmp   cl, 40h
                ; jnb   short RETZERO
                ; cmp   cl, 20h
                ; jnb   short MORE32
               shld    edx, eax, cl
               shl   eax, cl
               retn
; ---------------------------------------------------------------------------
MORE32:                                 ; CODE XREF: __allshl+8j
               mov   edx, eax
               xor   eax, eax
               and   cl, 1Fh
               shl   edx, cl
               retn
; ---------------------------------------------------------------------------
RETZERO:                              ; CODE XREF: __allshl+3j
               xor   eax, eax
               xor   edx, edx
               retn
                endp
```
简单来说,
被操作的2个uint 会循环N次,
每次操作
```c
c=(c<<1 | c>>31)   ^(c>>1 ^c>>12 ^c>>30)&1
c= c>>31|(c<<1)
```
差不多就是两个uint32 相互循环移位,附加c一个特殊的最低位XOR,条件是c的c.bit1 ^ c.bit12 ^ c.bit30 的异或 ;

得到这个算法以后写了个C代码测试,验证正确,结果又尝试了爆破,嗯,在编译器O2优化下 2mins/1W 计数;
不行,这个速度太慢了,于是按照逻辑写了个纯汇编的函数,手写的主要循环体优化后只有9行汇编代码,运行速度1mins/1W 计数,还是不够快

### 柳暗花明又一村
算法已知是迭代的,普通不能爆破,那就只能找算法的特性/漏洞了,比如通项函数什么的。
但是,上面的C表述基本不能看出什么;
于是就画了好几个算法运行的示意图

最后就这个看出端倪了。
!(draft1.jpg)

可以回代运算(N+1)项得到第N项;

核心是 c的n项的0~30bit在c的n+1项的1~31bit, cn项缺少的 31bit可以从c的n+1项的31,13,2和c的n+1项的最低位这四个东西异或得到;


C代码表述
```c
char* rolN_reverse(uint32_t* ptr, int cnt) {
      uint32_t n, n_1;
      n = ptr;
      n = ptr;
      printf("[-]Get: %X %X\n", n, n);
      for (int i = 0; i < cnt; i++) {
                n_1 = (n >> 1 & 0x7fffffff)|((n&1 ^ n>>31^ n>>13^ n>>2)&1)<<31;

                n_1 = (n >> 1 &0x7fffffff )|n<<31;
                n = n_1;
                n = n_1;
      }
      printf("[-]Rev: %X %X\n", n, n);
      ptr = n;
      ptr = n;
      return ptr;
}
```
写了个函数验证,结果正确;

不考虑奇怪的MD5,

最后把注册机(的½)写一下就是

```c
#define V0 0xA2BB
#define V1 0XA39A2EB8
#define V2 0XE8882542
#define V3 0X9DC4B870

#define CV0 0x255f35
#define CV1 0x24e918
#define CV2 0x2475dd

uint32_t knownArray = {V0,V1,V2,V3};
      rolN_reverse(knownArray + 2, CV2 );
      rolN_reverse(knownArray + 1, CV1);
      rolN_reverse(knownArray + 0, CV0);
      for (int i = 0; i < 4; i++) {
                printf(" 0x%X", knownArray);
      }
/*
[-]Get: E8882542 9DC4B870
[-]Rev: D4787858 54130406
[-]Get: A39A2EB8 D4787858
[-]Rev: 8C0D43AF 50B025BA
[-]Get: A2BB 8C0D43AF
[-]Rev: 2C6B2A6D EF4CABB9
input:0000
input:0x2C6B2A6D 0xEF4CABB9 0x50B025BA 0x54130406
*/   
```
所以,

!(https://attach.52pojie.cn/forum/201708/22/071449b2v11o3s2ivvg4vi.png)

成功完成任务;

期间各种奇奇怪怪的bug和错误歧途就不再描述了。。。

### Summary
- 内联汇编,x86 asm
- Z3符号引擎 不知道能不能用上帮助分析,手动分析汇编逻辑还是太慢了;
- 不要一条路走到黑,比如爆破什么的。~( ̄▽ ̄)~*
- 笔和草稿纸需常备案头,in case of something;
- ...


欢迎大家点评/闲聊

防止乱码在这里

撸了一个注册机,


这个CM.052终于完整了

whyida 发表于 2017-9-5 11:54

楼主是否可以贴暴力测试的代码。我测试没通过,感觉是指针问题。谢谢
#include <stdio.h>

#define V0 0x12345
#define V1 0X23456
#define V2 0X41A4309F
#define V3 0X6F6A7DCB

#define CV0 0x255f35
#define CV1 0x24e918
#define CV2 0x2475dd
typedef unsigned __int32 uint32_t;
int * rolN_reverse( int *Cptr,int Cconst1)
{       
/*
      uint32_t n, n_1;
      n = ptr;
      n = ptr;
      printf("[-]Get: %X %X\n", n, n);
      for (int i = 0; i < cnt; i++) {
                n_1 = (n >> 1 & 0x7fffffff)|((n&1 ^ n>>31^ n>>13^ n>>2)&1)<<31;

                n_1 = (n >> 1 &0x7fffffff )|n<<31;
                n = n_1;
                n = n_1;
      }
      printf("[-]Rev: %X %X\n", n, n);
      ptr = n;
      ptr = n;
      returnptr;
}      
*/
//      int b;
//v7=v1;
#define ptr 4
#define const1 8
      _asm{
               
              mov   eax,
              push    ebx
              mov   ebx, ;cnt;
              push        esi
              mov   esi, ;c
              push    esi
              mov   edi, ;c
              test        ebx, ebx
              push        ebp
                jbe   short loc_401C15
loop1:                           
               mov   ebp, edi
               mov   ecx, 1   
               shr   ebp, 1Fh
               mov   , ebp;
               mov   eax, esi
               mov   edx, edi
               xor   ebp, ebp      
               
               ;call    __allshl;            
               shld    edx, eax, cl
               shl   eax, cl

               mov   ecx,
               or      ebp, edx      
                                       
               or      ecx, eax      
               xor   edx, edx      
               mov   esi, ecx      
               mov   ecx, 0Bh      
               mov   eax, esi      
               mov   edi, ebp      
               and   eax, 4         
               
               ;call    __allshl
               shld    edx, eax, cl
               shl   eax, cl

               mov   ecx, esi      
               xor   ebp, ebp      
               and   ecx, 2000h   
                                       
               xor   edx, ebp      
               xor   eax, ecx      
                                       
               mov   ecx, 12h      
               
                ;call    __allshl
               shld    edx, eax, cl
               shl   eax, cl

               ;
               mov   ecx, esi      
               xor   edx, ebp      
               and   ecx, 80000000h
                                       
               xor   eax, ecx      
               
               mov   ecx, 1         
               ;call    __allshl
                shld    edx, eax, cl
                shl   eax, cl


               xor   esi, eax


               xor   edi, edx

               dec   ebx
               jnz   short loop1
               mov   eax,
               pop       ebp                                 

         loc_401C15:                           
               mov   , esi
               mov   , edi
               ;popad
               ;pop   edi
               ;pop   esi
               ;pop   ebx
               ;retn         

               

               
                popad
               
               
                }
#undef ptr
#undef const1
}

int main()
{       
      int knownArray = {V0,V1,V2,V3};
       
        rolN_reverse(knownArray + 2, CV2 );
        rolN_reverse(knownArray +1, CV1);
        rolN_reverse(knownArray +0, CV0);
       
        //for(int i = 0; i < 4; i++) {
      //       printf(" 0x%X", knownArray);
      //}
      
        return 0;
}

whyida 发表于 2017-9-5 21:01

代码测试通过,谢谢楼主。
#include <stdio.h>

#define V0 0x12345
#define V1 0X23456
#define V2 0X34567
#define V3 0X45678

#define CV0 0x255f35
#define CV1 0x24e918
#define CV2 0x2475dd

typedef unsigned __int32 uint32_t;
__declspec(naked) char * rolN_reverse(uint32_t *Cptr,int Cconst1)
{       
/*
      uint32_t n, n_1;
      n = ptr;
      n = ptr;
      printf("[-]Get: %X %X\n", n, n);
      for (int i = 0; i < cnt; i++) {
                n_1 = (n >> 1 & 0x7fffffff)|((n&1 ^ n>>31^ n>>13^ n>>2)&1)<<31;

                n_1 = (n >> 1 &0x7fffffff )|n<<31;
                n = n_1;
                n = n_1;
      }
      printf("[-]Rev: %X %X\n", n, n);
      ptr = n;
      ptr = n;
      returnptr;
}      
*/
//      int b;
//v7=v1;
#define ptr 4
#define const1 8
      _asm{
                mov        eax,
                push        ebx
                mov        ebx,
                push        esi
                mov        esi,
                push        edi
                mov        edi,
                test        ebx, ebx
                jbe        short loc_401C15
                push        ebp

loc_401BA5:                                ; CODE XREF: sub_401B90+7Ej
                mov        ebp, edi
                mov        ecx, 1
                shr        ebp, 1Fh
                mov        , ebp
                mov        eax, esi
                mov        edx, edi
                xor        ebp, ebp

                ;call        __allshl
                shld    edx, eax, cl
                shl   eax, cl
               
                mov        ecx,
                or        ebp, edx
                or        ecx, eax
                xor        edx, edx
                mov        esi, ecx
                mov        ecx, 0Bh
                mov        eax, esi
                mov        edi, ebp
                and        eax, 4
               
                ;call        __allshl

                shld    edx, eax, cl
                shl   eax, cl
               
                mov        ecx, esi
                xor        ebp, ebp
                and        ecx, 2000h
                xor        edx, ebp
                xor        eax, ecx
                mov        ecx, 12h
               
                ;call        __allshl

                shld    edx, eax, cl
                shl   eax, cl
               
                mov        ecx, esi
                xor        edx, ebp
                and        ecx, 80000000h
                xor        eax, ecx
                mov        ecx, 1
               
                ;call        __allshl

                shld    edx, eax, cl
                shl   eax, cl
               
                xor        esi, eax
                xor        edi, edx
                dec        ebx
                jnz        short loc_401BA5
                mov        eax,
                pop        ebp

loc_401C15:                                ; CODE XREF: sub_401B90+12j
                mov        , esi
                mov        , edi
                pop        edi
                pop        esi
                pop        ebx
                retn

                }
#undef ptr
#undef const1
}

int main()
{       
      uint32_t knownArray = {V0,V1,V2,V3};
       
        rolN_reverse(knownArray + 0, CV0 );
        rolN_reverse(knownArray +1, CV1);
        rolN_reverse(knownArray +2, CV2);
       
        for(int i = 0; i < 4; i++) {
             
               printf(" 0x%X", knownArray);
      }
      
        return 0;
}

zbnysjwsnd8 发表于 2017-8-22 09:09

好厉害啊
对了 五星难度和问号的 哪个难度高一些?

6767 发表于 2017-8-22 09:15

本帖最后由 6767 于 2017-8-22 10:14 编辑

zbnysjwsnd8 发表于 2017-8-22 09:09
好厉害啊
对了 五星难度和问号的 哪个难度高一些?
你可以做做那些带问号的,给出你的评分啊{:301_997:}
不加壳的话,难点就自我校验,暗桩,强力的混淆算法这几个了。



看了看160里面其他两个5星的,都是2000年左右写的,宏观上结构和现在这个差不多。

zbnysjwsnd8 发表于 2017-8-22 09:16

6767 发表于 2017-8-22 09:15
你可以做做那些带问号的,给出你的评分啊
不加壳的话,难点就自我校验,暗桩,强力的混淆算 ...

我做的几个带问号的注册方式都是serial的
好像都挺简单的
没有这个难(应该是我做的太少了

zbnysjwsnd8 发表于 2017-8-22 09:21

6767 发表于 2017-8-22 09:15
你可以做做那些带问号的,给出你的评分啊
不加壳的话,难点就自我校验,暗桩,强力的混淆算 ...

第90个和第132个
这个是我做的带问号的
我觉得没有楼主你玩的这个CM难

huangxu 发表于 2017-8-22 11:28

来学习一下,谢谢

ufo2273810 发表于 2017-8-22 16:10

谢谢分享。

Hmily 发表于 2017-8-22 17:55

就凭那手工图也要加个精华鼓励一下!{:1_926:}

guaiguai 发表于 2017-8-22 18:51

来学习了

Avenshy 发表于 2017-8-22 19:26

这图画的真好
页: [1] 2 3 4 5 6 7
查看完整版本: 【160 crackme 之52 】 注册码算法分析