首页
社区
课程
招聘
[原创]2016腾讯的游戏安全竞赛题PC第一题解答
发表于: 2016-3-13 12:42 13085

[原创]2016腾讯的游戏安全竞赛题PC第一题解答

2016-3-13 12:42
13085
近日看到腾讯的游戏安全竞赛题,利用业余时间搞了一下

从来没有写过注册机,对算法也不了解,看到这个题目就尝试弄了一下。顺便学习一下!

分析的是PC题目,要求写出注册机,不能爆破,打补丁!

题目链接:http://gslab.qq.com/competition/firstTurn.shtml

工具:OD,IDA,VC


注册失败是一个标签,不是MessageBox。老规矩先OD加载下断点
老规矩先OD加载对所有对话框下断点

咦?咋没断下来?
好那换一种思路,搜索【注册失败】字符串也没有
突然想到不管怎么样它的设置标签文本吧,那必须要先获取控件句柄才能操作。
GetDlgItem 函数下断点

00207A5C  /$  8BFF          mov edi,edi
00207A5E  |.  55            push ebp
00207A5F  |.  8BEC          mov ebp,esp
00207A61  |.  8379 4C 00    cmp dword ptr ds:[ecx+4C],0
00207A65  |.  75 16         jnz short Tencent2.00207A7D
00207A67  |.  FF75 08       push [arg.1]                             ; /ControlID
00207A6A  |.  FF71 20       push dword ptr ds:[ecx+20]               ; |hWnd
00207A6D  |.  FF15 98332200 call dword ptr ds:[<&USER32.GetDlgItem>] ; 断下返回\GetDlgItem

到这里接着跟
00201EFC   .  FFD7          call edi          ; \SendMessageA 发送 WM_GETTEXT消息获取
控件内容,也就是用户名和序列号

003CF2B8  00333231  123.
003CF3BC   ASCII "123123"
都获取到了,接着往下跟到这里 
00201F23   .  C64424 74 D7  mov byte ptr ss:[esp+74],0D7
00201F28   .  C64424 75 A2  mov byte ptr ss:[esp+75],0A2
00201F2D   .  C64424 76 B2  mov byte ptr ss:[esp+76],0B2
00201F32   .  C64424 77 E1  mov byte ptr ss:[esp+77],0E1
00201F37   .  885C24 78     mov byte ptr ss:[esp+78],bl
00201F3B   .  885C24 79     mov byte ptr ss:[esp+79],bl
00201F3F   .  885C24 7A     mov byte ptr ss:[esp+7A],bl
00201F43   .  885C24 7B     mov byte ptr ss:[esp+7B],bl
00201F47   .  885C24 7C     mov byte ptr ss:[esp+7C],bl
00201F4B   .  C64424 7D CA  mov byte ptr ss:[esp+7D],0CA
00201F50   .  C64424 7E A7  mov byte ptr ss:[esp+7E],0A7
00201F55   .  C64424 7F B0  mov byte ptr ss:[esp+7F],0B0
00201F5A   .  C68424 800000>mov byte ptr ss:[esp+80],0DC
00201F62   .  C68424 810000>mov byte ptr ss:[esp+81],0B3
00201F6A   .  C68424 820000>mov byte ptr ss:[esp+82],0C9
00201F72   .  C68424 830000>mov byte ptr ss:[esp+83],0B9
00201F7A   .  C68424 840000>mov byte ptr ss:[esp+84],0A6

看下堆栈这是什么?
003CF290  注册.....失败成功
原来在这里,怪不得搜索不到关键字符串 
char s[]="注册",char sa[]="失败成功"这样就搜不到字符串了。
继续
00201F90   .  8D47 FA       lea eax,dword ptr ds:[edi-6]
00201F93   .  83F8 0E       cmp eax,0E
00201F96   .  0F87 4B020000 ja Tencent2.002021E7             ;  关键失败跳转1
比较用户名长度小于6或大于20直接跳走到这里

002021E7   > \33C0          xor eax,eax   清空EAX
002021E9   >  8B5484 7D     mov edx,dword ptr ss:[esp+eax*4+7D] 这里是关键点
EAX=0指向失败字符 EAX=1指向成功
002021ED   .  8B4C24 54     mov ecx,dword ptr ss:[esp+54]
002021F1   .  8D4424 74     lea eax,dword ptr ss:[esp+74]
002021F5   .  50            push eax                                 ; /lParam
002021F6   .  53            push ebx                                 ; |wParam
002021F7   .  6A 0C         push 0C                                  ; |Message = WM_SETTEXT
002021F9   .  68 ED030000   push 3ED                                 ; |/Arg1 = 000003ED
002021FE   .  899424 880000>mov dword ptr ss:[esp+88],edx            ; ||
00202205   .  E8 52580000   call Tencent2.00207A5C                   ; |\Tencent2.00F07A5C
0020220A   .  8B48 20       mov ecx,dword ptr ds:[eax+20]            ; |
0020220D   .  51            push ecx                                 ; |hWnd
0020220E   .  FF15 24332200 call dword ptr ds:[<&USER32.SendMessageA>; \发送消息
到这里爆破点找到了 只要在002021E7   > \33C0          xor eax,eax   清空EAX这里修改EAX=1就显示注册成功了
当然还有别的方法爆破比如改跳转直接跳到MOV EAX,1 那个位置等等 由于要求写注册机这个就不多说了。
==================================
找到了关键CALL 上IDA
00201FE0   > /8BC1          mov eax,ecx
00201FE2   . |99            cdq
00201FE3   . |F7FF          idiv edi
00201FE5   . |8DB40C 880000>lea esi,dword ptr ss:[esp+ecx+88]
00201FEC   . |41            inc ecx
00201FED   . |0FBE8414 9C00>movsx eax,byte ptr ss:[esp+edx+9C]
00201FF5   . |8D142E        lea edx,dword ptr ds:[esi+ebp]
00201FF8   . |0FAFC2        imul eax,edx
00201FFB   . |0FAFC7        imul eax,edi
00201FFE   . |0106          add dword ptr ds:[esi],eax
00202000   . |83F9 10       cmp ecx,10
00202003   .^\7C DB         jl short Tencent2.00201FE0

直接到重点用户名第一段加密
IDA:
  do
  {
    v8 = v7 % v6;
    v9 = &v48[v7++];
    *(_DWORD *)v9 += v6 * (_DWORD)&v9[20160126 - (_DWORD)v48] * lParam[v8];
  }
  while ( v7 < 16 );

往下跟发现序列号长度也是有要求的,必须为27个字符否则直接跳转到失败
继续往下就是第二段的用户名加密了

用户名第二段加密
00202102   > /8B8C34 880000>mov ecx,dword ptr ss:[esp+esi+88]
00202109   . |B8 67666666   mov eax,66666667
0020210E   . |F7E9          imul ecx
00202110     |C1FA 02       sar edx,2
00202113   . |8BCA          mov ecx,edx
00202115   . |C1E9 1F       shr ecx,1F
00202118   . |03CA          add ecx,edx
0020211A   . |8B5424 24     mov edx,dword ptr ss:[esp+24]
0020211E   . |2BD7          sub edx,edi
00202120   . |894C34 2C     mov dword ptr ss:[esp+esi+2C],ecx
00202124   . |3BF2          cmp esi,edx
00202126   . |72 09         jb short Tencent2.00202131
00202128   . |E8 2DEF0000   call Tencent2.0021105A
0020212D   . |8B7C24 20     mov edi,dword ptr ss:[esp+20]
00202131   > |8B043E        mov eax,dword ptr ds:[esi+edi]
00202134   . |894434 40     mov dword ptr ss:[esp+esi+40],eax
00202138   . |83C6 04       add esi,4
0020213B   . |83FE 14       cmp esi,14
0020213E   .^\7C C2         jl short Tencent2.00202102

IDA:
 do
  {
    v16 = *(_DWORD *)&v48[v15] / 10;
    v17 = v23 - (_DWORD)v14;
    *(int *)((char *)&v25 + v15) = v16;
    if ( v15 >= (unsigned int)v17 )
    {
      _invalid_parameter_noinfo(v16);
      v14 = v22;
    }
    *(int *)((char *)&v30 + v15) = *(_DWORD *)((char *)v14 + v15);
    v15 += 4;
  }
  while ( v15 < 20 );//用户名二次加密

这下面一段就是关键算法和比较了对2次加密的用户名继续第三次加密比较
  if ( v34 + v25 != v32 || v32 + v26 != 2 * v34 || v33 + v27 != v30 || v30 + v28 != 2 * v33 || v29 + v31 != 3 * v27 )

经过分析这3段加密VC代码如下,代码有点搓,对付看吧 不要喷

//用户名生成系列号A
void CalcName(char *namestr)
{
  int strsize;
  int i=0;
  unsigned int a;
  BYTE stra[20] = { 0 };
  BYTE strb[20] = {0};
  BYTE *b;
  strsize = strlen(namestr);
  do
  {
    a = i % strsize;
    b = &strb[i++];
    *(DWORD *)b += strsize * (DWORD)&b[20160126 - (DWORD)strb] * namestr[a];
  } while (i < 16);
  i = 0;
  do
  {
    a = (unsigned int)*(DWORD *)&strb[i];
    __asm
    {      
      mov ecx, a
      mov eax, 66666667h
      imul ecx
      sar edx, 2
      mov ecx, edx
      shr ecx, 1Fh
      add ecx, edx
      mov a, ecx
    }  
    //a = (unsigned int)*(DWORD *)&strb[i] / (unsigned int)10;
    *(int *)((char *)&stra + i) = a;
    i += 4;
  } while (i < 20);
  *(DWORD*)&strb[16] = *(DWORD*)&stra[0] + *(DWORD*)&stra[4];
  *(DWORD*)&strb[12] = *(DWORD*)&stra[8] + *(DWORD*)&stra[12];
  *(DWORD*)&strb[8] = *(DWORD*)&strb[16] + *(DWORD*)&stra[0];
  *(DWORD*)&strb[0] = *(DWORD*)&stra[8] + *(DWORD*)&strb[12];
  *(DWORD*)&strb[4] = *(DWORD*)&stra[8] * 3 - *(DWORD*)&stra[16];
  memcpy(namestr, strb, 20);
}
其中有一段是用汇编写的 因为 第二次加密是每4字节 /10操作  
用C++    //a = *(DWORD *)&strb[i] / 10;这句会出现负数结果出错 请指教C++如何写才能实现编译后生成那段汇编  请回帖解答


加密用户名我们跟完事了,接下来是序列号的算法,因为不是明码比较!

从头跟起到这里:
通过序列号逐个字符查找在下面字符串中出现的位置保存下来作为加密数据。

01F61330 ASCII "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@%"

00201A7E  |.  E8 9D090000   ||call Tencent2.00202420 \序列号查找字符位置 call

这里就是加密上面生成的数据了。

00201A8D  |.>|mov ecx,dword ptr ss:[esp+18]           ;  加密1
00201A91  |.>|mov al,cl
00201A93  |.>|add al,al
00201A95  |.>|mov dl,ch
00201A97  |.>|shr dl,4
00201A9A  |.>|and dl,3
00201A9D  |.>|add al,al
00201A9F  |.>|add dl,al
00201AA1  |.>|mov al,byte ptr ss:[esp+1A]
00201AA5  |.>|mov byte ptr ss:[esp+14],dl
00201AA9  |.>|mov dl,al
00201AAB  |.>|shr dl,2
00201AAE  |.>|mov cl,ch
00201AB0  |.>|shl al,6
00201AB3  |.>|add al,byte ptr ss:[esp+1B]
00201AB7  |.>|and dl,0F
00201ABA  |.>|shl cl,4
00201ABD  |.>|xor dl,cl
00201ABF  |.>|mov byte ptr ss:[esp+15],dl
00201AC3  |.>|mov byte ptr ss:[esp+16],al
00201AC7    >xor edi,edi

IDA:

        v26 = 4 * v29 + ((BYTE1(v29) >> 4) & 3);
        v27 = 16 * BYTE1(v29) ^ (BYTE2(v29) >> 2) & 0xF;
        v28 = BYTE3(v29) + (BYTE2(v29) << 6);

由于是27个字符这里是对末尾最后3个字节处理
00201B6F  |.>mov ecx,dword ptr ss:[esp+18]            ;  加密2
00201B73  |.>mov al,cl
00201B75  |.>add al,al
00201B77  |.>add al,al
00201B79  |.>mov dl,ch
00201B7B  |.>shr dl,4
00201B7E  |.>and dl,3
00201B81  |.>add dl,al
00201B83  |.>mov al,byte ptr ss:[esp+1A]
00201B87  |.>mov byte ptr ss:[esp+14],dl
00201B8B  |.>mov dl,al
00201B8D  |.>shl al,6
00201B90  |.>add al,byte ptr ss:[esp+1B]
00201B94  |.>shr dl,2
00201B97  |.>mov byte ptr ss:[esp+16],al
00201B9B  |.>mov eax,dword ptr ss:[esp+20]
00201B9F  |.>mov cl,ch
00201BA1  |.>and dl,0F
00201BA4  |.>shl cl,4
00201BA7  |.>dec eax
00201BA8  |.>xor dl,cl
00201BAA  |.>xor ebx,ebx
00201BAC  |.>mov byte ptr ss:[esp+15],dl
00201BB0  |.>mov dword ptr ss:[esp+24],eax
00201BB4  |.>test eax,eax

IDA:
      v26 = 4 * v29 + ((BYTE1(v29) >> 4) & 3);
      v28 = BYTE3(v29) + (BYTE2(v29) << 6);
      result = v31 - 1;
      v21 = 0;
      v27 = 16 * BYTE1(v29) ^ (BYTE2(v29) >> 2) & 0xF;

2段算法基本一样 只是对最后一个字节FF填充处理

这2段加密算法是把逐个4字节数据加密成3字节数据,最后由于是27个字节最后3个字节末尾加上FF 加密
加密后的数据取前20个字节 和前面用户名生成的进行比较。

先逆向出解密算法 然后从ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@%
逐个查找对应位置的字符 这样就生成了系列号

逆向出的生成 算法代码
----------------------------------
//加密成序列号
void CalcSN(char *stra)
{
  char v25;
  char v26;
  char v27;
  char v28;
  BYTE v1[25] = { 0 };
  memcpy(v1, stra, 21);
  v1[21] = { 0x3F };
  int v2;
  char abc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@%";
  char codes[260];
  char a[260];
  memset(a, 0, 260);
  memset(codes, 0, 260);
  for (int i = 0; i < 21;i+=3)
  {
    if (i==18)//特殊处理最后3位
    {
      v25 = v1[i] / 4;
      //v28 = v1[i + 2] % 0X40;
      v28 = 0xFF;
      v2 = (BYTE(v1[i + 1]) & 0xF) << 8;
      v27 = (v2 + 0x40) >> 6;
      v2 = (v1[i] % 4) << 4;
      v26 = v2 ^ (BYTE(v1[i + 1]) >> 4);
      a[0] = abc[v25];
      strcat_s(codes, a);
      a[0] = abc[v26];
      strcat_s(codes, a);
      a[0] = abc[v27];
      strcat_s(codes, a);
      a[0] = 0;
      strcat_s(codes, a);
    } 
    else
    {
      v25 = v1[i] / 4;
      v28 = v1[i + 2] % 0X40;
      v2 = (BYTE(v1[i + 1]) & 0xF) << 8;
      v27 = (v2 + (v1[i + 2] - v28)) >> 6;
      v2 = (v1[i] % 4) << 4;
      v26 = v2 ^ (BYTE(v1[i + 1]) >> 4);
      a[0] = abc[v25];
      strcat_s(codes, a);
      a[0] = abc[v26];
      strcat_s(codes, a);
      a[0] = abc[v27];
      strcat_s(codes, a);
      a[0] = abc[v28];
      strcat_s(codes, a);
    }

  }

  memset(stra, 0, 200);
  memcpy(stra, codes, strlen(codes));
}
-------------------------

void CMFCApplication1Dlg::OnBnClickedButton1()
{
  // TODO:  在此添加控件通知处理程序代码
  CString myname;
  char namem[260];
  medit1.GetWindowTextA(myname);
  strcpy_s(namem, myname);
  if (strlen(namem) >= 6 && strlen(namem) <= 20)
  {
    CalcName(namem);//用户名生成系列号A
    CalcSN(namem);//加密成序列号
    medit2.SetWindowTextA(namem);
  }else AfxMessageBox("用户名太长或太短!");
}

好到这里 整个注册机 就完成了!



总结:
1,SendMessageA 发送 WM_GETTEXT消息获取控件文本一般的断点断不下来,给新手增加
了些难度
2,从用户名到生成序列号 要用4段不同的算法,有一定的难度,不过加密代码清晰还是不难分析

3,附件1,VC2013编译代码。附件2,注册机,附件3   题目

最后第一次发帖排版有些乱 ,表达不到位的地方欢迎指正!

[课程]FART 脱壳王!加量不加价!FART作者讲授!

上传的附件:
收藏
免费 3
支持
分享
最新回复 (28)
雪    币: 163
活跃值: (103)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
2
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@%"最长的位置是0x3F,二进制最长6BIT,所以可以把4个字节压缩成3个字节,当时我在把3个字节还原成4个字节的时候,花了点时间。话说第一轮的结果出来没有?

上传的附件:
2016-3-13 12:53
0
雪    币: 68
活跃值: (104)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
是的 3个字节还原4个字节我也是花时间最多的哈,结果是14号公布吧 不过我看到题的时候是9号了,9号24:00提交 ,咱不是学生这能围观了
2016-3-13 12:59
0
雪    币: 55
活跃值: (934)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
只能膜拜一下了
2016-3-13 13:16
0
雪    币: 144
活跃值: (178)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
围观一下,分享实录
2016-3-13 18:58
0
雪    币: 44229
活跃值: (19965)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
6
编辑了一下你的帖,把题目上传上来了。
2016-3-13 19:34
0
雪    币: 68
活跃值: (104)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
第一次传附件 弄的乱七八糟   谢谢坛主大大帮忙
2016-3-13 20:00
0
雪    币: 423
活跃值: (501)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
小弟刚刚初学逆向这些,根据大哥的提示也成功断到大哥那些地址,跟大哥上面一致,我想用直接爆破跳转去修改这个程序,联系下,但是出现了一点疑问..求指点下,
我直接跳转到 xor eax,eax  然后把直接强行把eax赋值1,改成 mov eax,1



然后往下面跟踪 也发现 eax的值修改为1



但是程序运行后,提示的确实乱码,我不太理解,求解答

2016-3-14 04:09
0
雪    币: 1176
活跃值: (1234)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
9
首先你破坏了汇编指令那就肯定错了。

------------------------------------------
在我选中的指令处下端点,然后寄存器窗口-ESP-右键“数据窗口跟随”-再看数据窗口:
你会发现账户名,然后继续单步下去的话会看见字符串注册失败成功 往下在拉一些就可以看见你输入的序列号。


在楼主说的xor,eax.eax处下个断点,F9-F8-寄存器窗口修改eax为1


往下走一步


结果:


再试试?
上传的附件:
2016-3-14 10:04
0
雪    币: 423
活跃值: (501)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
置1是可以的提示注册成功的 可是我就是想这种内存修改代码试试 楼主已经公布了算法的了 所以自己想试试内存改代码的
2016-3-14 11:44
0
雪    币: 1176
活跃值: (1234)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
11
那就JMP或CALL更改。
2016-3-14 12:02
0
雪    币: 68
活跃值: (104)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
12
003821E4      83C4 04       add esp,4
003821E7      33C0          xor eax,eax  这个汇编指令只占内存2个字节
003821E9      8B5484 7D     mov edx,dword ptr ss:[esp+eax*4+7D]
003821ED   .  8B4C24 54     mov ecx,dword ptr ss:[esp+54]

你修改成 mov eax,1 是占5个字节的
破坏了mov edx,dword ptr ss:[esp+eax*4+7D]这条指令 这是通过指针取失败成功的字符的 你破坏了 就造成  没有取堆栈的字符 直接压栈EDX 显示乱码了

你可以这样爆破,在判断用户名长度跳转这里直接JMP到  003821E4。
003821E4      83C4 04    add esp,4  这里是3个字节+上下面xor eax,eax  正好是5个字节
003821E7      33C0         xor eax,eax  这个汇编指令只占内存2个字节

00381F96     /0F87 4B020000 ja Tencent2.003821E7   ;  原来的
00381F9C   . |33C0          xor eax,eax

00381F93   .  83F8 0E       cmp eax,0E
00381F96    - E9 7962CBFF   jmp 00038214       修改后JMP无条件跳转,不管用户名长度如何都跳到成功

003821DF   .  E8 C30A0000   call Tencent2.00382CA7
003821E4      B8 01000000   mov eax,1   //修改后没有破坏下面要执行的指令
003821E9      8B5484 7D     mov edx,dword ptr ss:[esp+eax*4+7D]
003821ED   .  8B4C24 54     mov ecx,dword ptr ss:[esp+54]
003821F1   .  8D4424 74     lea eax,dword ptr ss:[esp+74]
2016-3-14 14:10
0
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
为什么我在
IsDebuggerPresent
下断点不走呢?
2016-3-14 14:27
0
雪    币: 443
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
楼主试试上面内联汇编部分换成下面这样能不能生成你要的,我只是个新手,如果说错了,不要骂我
a = *(int*)&strb[i] / 10;
2016-3-14 14:53
0
雪    币: 68
活跃值: (104)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
15
[QUOTE=gs笨笨;1419862]楼主试试上面内联汇编部分换成下面这样能不能生成你要的,我只是个新手,如果说错了,不要骂我
a = *(int*)&strb[i] / 10;[/QUOTE]

楼上正解 测试通过
2016-3-14 17:04
0
雪    币: 219
活跃值: (1634)
能力值: ( LV9,RANK:410 )
在线值:
发帖
回帖
粉丝
16
分析的不错,支持一下
2016-3-14 19:03
0
雪    币: 423
活跃值: (501)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
17
[QUOTE=wliupengw;1419846]003821E4      83C4 04       add esp,4
003821E7      33C0          xor eax,eax  这个汇编指令只占内存2个字节
003821E9      8B5484 7D     mov edx,dword ptr ss:[esp...[/QUOTE]

明白了, 谢谢大哥~测试通过
2016-3-14 19:43
0
雪    币: 229
活跃值: (89)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
18
不对呀,楼主,我看你3个恢复四个时候,好像不是它那个加密算法的逆运算呀,                miadie[0]=neu_lastword21[i*3+0];
                miadie[1]=neu_lastword21[i*3+1];
                miadie[2]=neu_lastword21[i*3+2];
                password[2+i*4]=0x20;
                password[3+i*4]=miadie[2]-password[2+i*4]<<6;//((miadie[1]^((password[1+i*4]<<4)))&0xf)<<2;
                password[1+i*4]=(miadie[1]^((password[2+i*4]>>2)&0xf))>>4;
                password[0+i*4]=(miadie[0]-((password[1+i*4]>>4)&3))%4;
我这样算不知道为什么得不到正解呀
2016-3-16 20:15
0
雪    币: 229
活跃值: (89)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
19
楼主,我就是密码还原部分不懂,而且也没有看懂你的思路哦,好像你没有严格按照加密的逆运算来搞,而且好像很多你都是直接当0的,能讲解一下吗
2016-3-16 20:40
0
雪    币: 284
活跃值: (3394)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
20
你说有段汇编怎么用C++写,那个是指令里有个算数右移sar,牵扯的符号位的问题,那个变量a要定义为有符号数int
2016-3-18 02:08
0
雪    币: 68
活跃值: (104)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
21
嗯,搞明白了。 就是一个有符号除法 我没有转换有符号类型才出错
2016-3-19 19:40
0
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
我也是断在GetDlgItem这里,一直F8下去,堆栈都没有出现过注册成功或者失败的字样诶,是不是要跟进call里面的?
2016-3-19 22:22
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
不错不错
2016-3-21 01:01
0
雪    币: 229
活跃值: (89)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
24
是不是说要看出它的左移右移要看出是哪一种乘除运算,再做反向运算?不一定对照着汇编做反向运算????
2016-3-21 14:44
0
雪    币: 229
活跃值: (89)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
25
是不是说做算法反向的时候,需要看懂那些左移右移代表的乘除含义,再做运算级的反向?不要做汇编级的反向?
2016-3-21 14:46
0
游客
登录 | 注册 方可回帖
返回
//