逆向分析 160个CrackMe五星052

#逆向分析 160个CrackMe 052

闲来无事,工作上有调整,等待来年安排,日常的学习还是不能松懈,好久没搞2进制了,最近正在刷pwn和CrackMe,看到了一个160集合感觉不错,刷了几周了,做了20多个了吧,也不知道哪个好,随便搞了下,感觉这5星级的还是挺有意思的,故分析发文。

工具和环境

环境:win10 x64 chs

工具:x64dbg IDA BinaryNinja

编译器:gcc

大体扫一眼

  • 看图标和UI应该是mfc的。
  • 类型应该是Name/Serail类型的。
  • DIE跑一下:UPX的壳。
  • 简单输入Name和Serial测试下,有弹窗。

脱壳

那些在xp上好有用的工具都不太兼容win10,魔改版的LoadPE + ImportREC 修复的exe时灵时不灵的。

还好x64dbg仅有的一个插件解决了这个问题。

x64dbg + esp定律找到OEP,使用x64dbg自带的Scylla,三下五除二搞定。

 

 

找算法函数

第一种办法就是 IDA根据导入表MessageBox函数,交叉引用找到算法。

第二种就是通过OD或者x64dbg动态调试,弹出对话框后,暂停进程,调用栈回溯,也能找到算法函数。

这里我就不过多赘述。

分析

直接拖入IDA,通过导入表MessageBoxA的交叉引用找到4处引用,2个函数。

第一个函数是MFC封装的MsgBox函数,根据它的交叉引用很快找到了数据处理和比较的地方。

封装的MsgBox

1

2

3

4

5

6

7

8

9

10

11

12

13

14

int __thiscall sub_4100A8(_DWORD *this, LPCSTR lpText, LPCSTR lpCaption, UINT uType)

{

  const CHAR *v4; // eax

  HWND v6; // ecx

  v4 = lpCaption;

  if ( !lpCaption )

    v4 = (const CHAR *)*((_DWORD *)AfxGetModuleState() + 4);

  if ( this )

    v6 = (HWND)this[7];

  else

    v6 = 0;

  return MessageBoxA(v6, lpText, v4, uType);

}

根据MsgBox交叉引用,找到处理函数

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

UPX0:00401C20 sub     esp, 608h

UPX0:00401C26 push    ebx

UPX0:00401C27 push    ebp

UPX0:00401C28 push    esi

UPX0:00401C29 mov     ebp, ecx

UPX0:00401C2B push    edi

UPX0:00401C2C mov     ecx, 7Dh ; '}'

UPX0:00401C31 xor     eax, eax

UPX0:00401C33 lea     edi, [esp+3Ch]

UPX0:00401C37 rep stosd

UPX0:00401C39 mov     ecx, 7Dh ; '}'

UPX0:00401C3E lea     edi, [esp+424h]

UPX0:00401C45 rep stosd

UPX0:00401C47 mov     ecx, 7Dh ; '}'

UPX0:00401C4C lea     edi, [esp+230h]

UPX0:00401C53 rep stosd

UPX0:00401C55 lea     eax, [esp+3Ch]

UPX0:00401C59 push    64h ; 'd'

UPX0:00401C5B push    eax

UPX0:00401C5C lea     ecx, [ebp+5Ch]

UPX0:00401C5F call    MfcGetText                      ;  获取Name的字符串 name = esp + 3c

UPX0:00401C64 lea     ecx, [esp+424h]

UPX0:00401C6B push    64h ; 'd'

UPX0:00401C6D push    ecx

UPX0:00401C6E lea     ecx, [ebp+0ACh]

UPX0:00401C74 call    MfcGetText                      ; 获取Code的字符串存在 esp + 0x424

UPX0:00401C79 lea     edi, [esp+3Ch]

UPX0:00401C7D or      ecx, 0FFFFFFFFh

UPX0:00401C80 xor     eax, eax

UPX0:00401C82 lea     edx, [esp+230h]

UPX0:00401C89 repne scasb

UPX0:00401C8B not     ecx                             ; 求name长度

UPX0:00401C8D sub     edi, ecx

UPX0:00401C8F mov     eax, ecx

UPX0:00401C91 mov     esi, edi

UPX0:00401C93 mov     edi, edx

UPX0:00401C95 shr     ecx, 2

UPX0:00401C98 rep movsd                               ; name复制到esp+230h

UPX0:00401C9A mov     ecx, eax

UPX0:00401C9C and     ecx, 3

UPX0:00401C9F rep movsb

UPX0:00401CA1 lea     ecx, [esp+230h]

UPX0:00401CA8 push    ecx

UPX0:00401CA9 call    __strrev                        ; 将name反转

UPX0:00401CAE lea     edi, [esp+234h]

UPX0:00401CB5 or      ecx, 0FFFFFFFFh

UPX0:00401CB8 xor     eax, eax

UPX0:00401CBA add     esp, 4

UPX0:00401CBD repne scasb

UPX0:00401CBF not     ecx                             ; 求反转后长度

UPX0:00401CC1 sub     edi, ecx

UPX0:00401CC3 lea     edx, [esp+3Ch]

UPX0:00401CC7 mov     esi, edi

UPX0:00401CC9 mov     ebx, ecx

UPX0:00401CCB mov     edi, edx

UPX0:00401CCD or      ecx, 0FFFFFFFFh

UPX0:00401CD0 repne scasb

UPX0:00401CD2 mov     ecx, ebx

UPX0:00401CD4 dec     edi

UPX0:00401CD5 shr     ecx, 2

UPX0:00401CD8 rep movsd                               ; strcat(name,strrev(name))

UPX0:00401CDA mov     ecx, ebx

UPX0:00401CDC lea     eax, [esp+18h]

UPX0:00401CE0 and     ecx, 3

UPX0:00401CE3 push    eax

UPX0:00401CE4 push    offset aSoftwareMicros          ; "SOFTWARE\\Microsoft\\Windows\\CurrentVe"...

UPX0:00401CE9 push    80000002h

UPX0:00401CEE rep movsb

UPX0:00401CF0 call    ds:RegOpenKeyA                  ; 打开注册表

UPX0:00401CF6 mov     ebx, ds:RegQueryValueExA        ; 查询ProductID

UPX0:00401CFC lea     ecx, [esp+14h]

UPX0:00401D00 lea     edx, [esp+230h]

UPX0:00401D07 push    ecx

UPX0:00401D08 mov     ecx, [esp+1Ch]

UPX0:00401D0C lea     eax, [esp+14h]

UPX0:00401D10 push    edx

UPX0:00401D11 push    eax

UPX0:00401D12 push    0

UPX0:00401D14 push    offset aProductid               ; "ProductID"

UPX0:00401D19 mov     dword ptr [esp+24h], 1

UPX0:00401D21 mov     dword ptr [esp+28h], 100h

UPX0:00401D29 push    ecx

UPX0:00401D2A call    ebx ; RegQueryValueExA          ; 查询ProductID

UPX0:00401D2C lea     edi, [esp+230h]

UPX0:00401D33 or      ecx, 0FFFFFFFFh

UPX0:00401D36 xor     eax, eax

UPX0:00401D38 lea     edx, [esp+3Ch]

UPX0:00401D3C repne scasb

UPX0:00401D3E not     ecx

UPX0:00401D40 sub     edi, ecx

UPX0:00401D42 mov     dword ptr [esp+10h], 1

UPX0:00401D4A mov     esi, edi

UPX0:00401D4C mov     edi, edx

UPX0:00401D4E mov     edx, ecx

UPX0:00401D50 or      ecx, 0FFFFFFFFh

UPX0:00401D53 repne scasb

UPX0:00401D55 mov     ecx, edx

UPX0:00401D57 dec     edi

UPX0:00401D58 shr     ecx, 2

UPX0:00401D5B rep movsd                               ; 将查询的字符串strcat到name

UPX0:00401D5D mov     ecx, edx

UPX0:00401D5F lea     eax, [esp+14h]

UPX0:00401D63 and     ecx, 3

UPX0:00401D66 push    eax

UPX0:00401D67 mov     eax, [esp+1Ch]

UPX0:00401D6B lea     edx, [esp+14h]

UPX0:00401D6F rep movsb

UPX0:00401D71 lea     ecx, [esp+234h]

UPX0:00401D78 mov     dword ptr [esp+18h], 100h

UPX0:00401D80 push    ecx

UPX0:00401D81 push    edx

UPX0:00401D82 push    0

UPX0:00401D84 push    offset aRegisteredowne          ; "RegisteredOwner"

UPX0:00401D89 push    eax

UPX0:00401D8A call    ebx ; RegQueryValueExA          ; 查询RegisteredOwner

UPX0:00401D8C lea     edi, [esp+230h]

UPX0:00401D93 or      ecx, 0FFFFFFFFh

UPX0:00401D96 xor     eax, eax

UPX0:00401D98 lea     edx, [esp+3Ch]

UPX0:00401D9C repne scasb

UPX0:00401D9E not     ecx                             ; 求注册表查询字符串长度

UPX0:00401DA0 sub     edi, ecx

UPX0:00401DA2 mov     esi, edi

UPX0:00401DA4 mov     ebx, ecx

UPX0:00401DA6 mov     edi, edx

UPX0:00401DA8 or      ecx, 0FFFFFFFFh

UPX0:00401DAB repne scasb

UPX0:00401DAD mov     ecx, ebx

UPX0:00401DAF dec     edi

UPX0:00401DB0 shr     ecx, 2

UPX0:00401DB3 rep movsd

UPX0:00401DB5 mov     ecx, ebx

UPX0:00401DB7 and     ecx, 3

UPX0:00401DBA rep movsb                               ; 将查询的字符串strcat到name

UPX0:00401DBC lea     edi, [esp+3Ch]                  ; 由于win10缺少这几个注册表项,其得到的name= name + strrev(name) +strrev(name) + strrev(name)

UPX0:00401DC0 or      ecx, 0FFFFFFFFh                 ; 如果xp下应该是 name + strrev(name) + ProducID(查询得到字符串) + RegisterOwner(查询的字符串)

UPX0:00401DC3 repne scasb

UPX0:00401DC5 not     ecx                             ; 求组合后的长度

UPX0:00401DC7 lea     eax, [esp+2Ch]

UPX0:00401DCB dec     ecx

UPX0:00401DCC push    eax

UPX0:00401DCD mov     esi, ecx

UPX0:00401DCF call    Md5InitState                    ; 初始化md5的4个state

UPX0:00401DD4 lea     edx, [esp+esi+40h]

UPX0:00401DD8 mov     ecx, 13h

UPX0:00401DDD xor     eax, eax

UPX0:00401DDF mov     edi, edx

UPX0:00401DE1 rep stosd                               ; 清空name后面19 * 4 字节

UPX0:00401DE3 add     esp, 4

UPX0:00401DE6 inc     esi

UPX0:00401DE7 stosw

UPX0:00401DE9 mov     ecx, esi

UPX0:00401DEB stosb

UPX0:00401DEC and     ecx, 3Fh                        ; 对齐数据64

UPX0:00401DEF mov     eax, 40h ; '@'                  ; 对齐数据64

UPX0:00401DF4 sub     eax, ecx                        ; 对齐数据64

UPX0:00401DF6 mov     byte ptr [edx], 80h ; '€'       ; name最后结尾赋值0x80

UPX0:00401DF9 cmp     eax, 7                          ; 对齐数据64

UPX0:00401DFC jg      short loc_401E01

UPX0:00401DFE add     eax, 40h ; '@'                  ; 对齐数据64

UPX0:00401E01

UPX0:00401E01 loc_401E01:                             ; CODE XREF: UPX0:00401DFC↑j

UPX0:00401E01 add     esi, eax

UPX0:00401E03 lea     edi, [esp+3Ch]

UPX0:00401E07 or      ecx, 0FFFFFFFFh

UPX0:00401E0A xor     eax, eax

UPX0:00401E0C repne scasb

UPX0:00401E0E not     ecx

UPX0:00401E10 dec     ecx

UPX0:00401E11 xor     edi, edi

UPX0:00401E13 shl     ecx, 3                          ; 长度*8

UPX0:00401E16 test    esi, esi

UPX0:00401E18 mov     [esp+esi+34h], ecx              ; 添加长度数据

UPX0:00401E1C jle     short loc_401E37

UPX0:00401E1E

UPX0:00401E1E loc_401E1E:                             ; CODE XREF: UPX0:00401E35↓j

UPX0:00401E1E lea     edx, [esp+2Ch]

UPX0:00401E22 lea     eax, [esp+edi+3Ch]

UPX0:00401E26 push    edx

UPX0:00401E27 push    eax

UPX0:00401E28 call    Md5Transform                    ; md5Transform

UPX0:00401E2D add     edi, 40h ; '@'                  ; 递增64字节

UPX0:00401E30 add     esp, 8

UPX0:00401E33 cmp     edi, esi

UPX0:00401E35 jl      short loc_401E1E                ; for(i=0;i < esi(对齐长度);i +=64)

UPX0:00401E37

UPX0:00401E37 loc_401E37:                             ; CODE XREF: UPX0:00401E1C↑j

UPX0:00401E37 mov     ebx, [esp+2Ch]

UPX0:00401E3B lea     ecx, [esp+28h]

UPX0:00401E3F lea     edx, [esp+24h]

UPX0:00401E43 push    ecx

UPX0:00401E44 lea     eax, [esp+24h]

UPX0:00401E48 push    edx

UPX0:00401E49 lea     ecx, [esp+24h]

UPX0:00401E4D push    eax

UPX0:00401E4E push    ecx

UPX0:00401E4F lea     edx, [esp+434h]                

UPX0:00401E56 and     ebx, 0FFFFh                     ; 将state[0]的高位抹去

UPX0:00401E5C push    offset aLxLxLxLx                ; "%lx%lx%lx%lx"

UPX0:00401E61 push    edx

UPX0:00401E62 mov     [esp+44h], ebx

UPX0:00401E66 call    _sscanf                         ; 从code字符串中获取4个UINT数据

UPX0:00401E6B add     esp, 18h

UPX0:00401E6E cmp     eax, 4                          ; 不够4个就报错

UPX0:00401E71 jz      short loc_401E91

UPX0:00401E73 push    30h ; '0'

UPX0:00401E75 push    offset aFailed                  ; "Failed"

UPX0:00401E7A push    offset aHmmmYouDonTEve          ; "... Hmmm, you don't even pass the first"...

UPX0:00401E7F mov     ecx, ebp

UPX0:00401E81 call    MfcMsgBox

UPX0:00401E86 pop     edi

UPX0:00401E87 pop     esi

UPX0:00401E88 pop     ebp

UPX0:00401E89 pop     ebx

UPX0:00401E8A add     esp, 608h

UPX0:00401E90 retn

UPX0:00401E91 ; ---------------------------------------------------------------------------

UPX0:00401E91

UPX0:00401E91 loc_401E91:                             ; CODE XREF: UPX0:00401E71↑j

UPX0:00401E91 xor     esi, esi

UPX0:00401E93 lea     edi, [esp+1Ch]

UPX0:00401E97

UPX0:00401E97 loc_401E97:                             ; CODE XREF: UPX0:00401EB3↓j

UPX0:00401E97 mov     eax, 0BADC0DEh                  ; for(i=0;i < 3;i++)

UPX0:00401E9C lea     ecx, [esi+50h]

UPX0:00401E9F cdq

UPX0:00401EA0 idiv    ecx                             ; loop_cnt = 0xbadc0de / (i + 80)

UPX0:00401EA2 push    eax

UPX0:00401EA3 push    edi

UPX0:00401EA4 call    Encode                          ; 算法关键:将4个UINT做3轮ENcode

UPX0:00401EA9 add     esp, 8

UPX0:00401EAC inc     esi

UPX0:00401EAD add     edi, 4

UPX0:00401EB0 cmp     esi, 3

UPX0:00401EB3 jl      short loc_401E97                ; for(i=0;i < 3;i++)

UPX0:00401EB5 xor     eax, eax

UPX0:00401EB7

UPX0:00401EB7 loc_401EB7:                             ; CODE XREF: UPX0:00401EC9↓j

UPX0:00401EB7 mov     edx, [esp+eax+1Ch]

UPX0:00401EBB mov     ecx, [esp+eax+2Ch]

UPX0:00401EBF cmp     edx, ecx

UPX0:00401EC1 jnz     short loc_401EE9

UPX0:00401EC3 add     eax, 4

UPX0:00401EC6 cmp     eax, 10h

UPX0:00401EC9 jl      short loc_401EB7

UPX0:00401ECB push    40h ; '@'

UPX0:00401ECD push    offset aWelcome                 ; "Welcome"

UPX0:00401ED2 push    offset aManYouReGoodEn          ; "... Man, you're good enough to join COR"...

UPX0:00401ED7 mov     ecx, ebp

UPX0:00401ED9 call    MfcMsgBox

UPX0:00401EDE pop     edi

UPX0:00401EDF pop     esi

UPX0:00401EE0 pop     ebp

UPX0:00401EE1 pop     ebx

UPX0:00401EE2 add     esp, 608h

UPX0:00401EE8 retn

UPX0:00401EE9 ; ---------------------------------------------------------------------------

UPX0:00401EE9

UPX0:00401EE9 loc_401EE9:                             ; CODE XREF: UPX0:00401EC1↑j

UPX0:00401EE9 push    30h ; '0'

UPX0:00401EEB push    offset aFailed                  ; "Failed"

UPX0:00401EF0 push    offset aBetterLuckNext          ; "... Better luck next time ..."

UPX0:00401EF5 mov     ecx, ebp

UPX0:00401EF7 call    MfcMsgBox

UPX0:00401EFC pop     edi

UPX0:00401EFD pop     esi

UPX0:00401EFE pop     ebp

UPX0:00401EFF pop     ebx

UPX0:00401F00 add     esp, 608h

UPX0:00401F06 retn

代码分析:

  • 获取name和code分别保存

  • name + strrev(name) + ProductID(项的值) + RegisterOwner(项的值);由于是win10没有注册表项, 最终结果是 name + strrev(name) + strrev(name) + strrev(name) ;

  • 初始化md5的state

  • name[-1] = 0x80 ;数据对齐64字节,存储len * 8

  • 循环Md5Tramsform

  • 保留state[0] 低16位,关键跳比较的就是state[0]的数据

  • 读取code中的4个UINT

  • 分别对 UINT[0] UINT[1];UINT[1]UINT[2];UINT[2]UINT[3] 运算

  • 比较 UINT[0] 和 state[0] 如果相等则成功;

Encode函数

关键函数Encode函数

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

UPX0:00401B90 Encode proc near                        ; CODE XREF: UPX0:00401EA4↓p

UPX0:00401B90

UPX0:00401B90 arg_0= dword ptr  4

UPX0:00401B90 arg_4= dword ptr  8

UPX0:00401B90

UPX0:00401B90 mov     eax, [esp+arg_0]

UPX0:00401B94 push    ebx

UPX0:00401B95 mov     ebx, [esp+4+arg_4]

UPX0:00401B99 push    esi

UPX0:00401B9A mov     esi, [eax]

UPX0:00401B9C push    edi

UPX0:00401B9D mov     edi, [eax+4]

UPX0:00401BA0 test    ebx, ebx

UPX0:00401BA2 jbe     short loc_401C15

UPX0:00401BA4 push    ebp                             ; edi = 32位UINT

UPX0:00401BA4                                         ; esi = 32位UINT

UPX0:00401BA5

UPX0:00401BA5 loc_401BA5:                             ; CODE XREF: Encode+7E↓j

UPX0:00401BA5 mov     ebp, edi                        ; for(i=0;i<loop_cnt;i++)

UPX0:00401BA5                                         ; 第一步就是实现2个UINT的循环左移1

UPX0:00401BA7 mov     ecx, 1

UPX0:00401BAC shr     ebp, 1Fh

UPX0:00401BAF mov     [esp+10h+arg_4], ebp            ; 取高32位最高位,保存一下

UPX0:00401BB3 mov     eax, esi

UPX0:00401BB5 mov     edx, edi

UPX0:00401BB7 xor     ebp, ebp

UPX0:00401BB9 call    __allshl                        ; 2个UINT实现左移1

UPX0:00401BBE mov     ecx, [esp+10h+arg_4]            ; 再将保存的的高32位的最高一位给低32位的最低位,实现循环左移

UPX0:00401BC2 or      ebp, edx

UPX0:00401BC4 or      ecx, eax

UPX0:00401BC6 xor     edx, edx

UPX0:00401BC8 mov     esi, ecx                        ; 循环左移结束

UPX0:00401BCA mov     ecx, 0Bh                        ; 后面就是取低32位的第2 13 31位做亦或

UPX0:00401BCF mov     eax, esi

UPX0:00401BD1 mov     edi, ebp

UPX0:00401BD3 and     eax, 4                          ; 取低32位数据 2

UPX0:00401BD6 call    __allshl                        ; 循环做移动1111 + 2 = 13

UPX0:00401BDB mov     ecx, esi

UPX0:00401BDD xor     ebp, ebp

UPX0:00401BDF and     ecx, 2000h                      ; 取低32位数据 13

UPX0:00401BE5 xor     edx, ebp

UPX0:00401BE7 xor     eax, ecx                        ; 然后 亦或

UPX0:00401BE9 mov     ecx, 12h                        ; 循环做移动18位  13 + 18 = 31

UPX0:00401BEE call    __allshl

UPX0:00401BF3 mov     ecx, esi

UPX0:00401BF5 xor     edx, ebp

UPX0:00401BF7 and     ecx, 80000000h                  ; 取低32位数据 31

UPX0:00401BFD xor     eax, ecx                        ; eax = eax ^ 31位的值

UPX0:00401BFF mov     ecx, 1

UPX0:00401C04 call    __allshl                        ; 左移动一位将,亦或结果存入edx

UPX0:00401C09 xor     esi, eax                        ; eax 不管是0还是0x8000000左移1位后总是0

UPX0:00401C0B xor     edi, edx                        ; 高32位的最后一位和亦或结果做亦或

UPX0:00401C0D dec     ebx

UPX0:00401C0E jnz     short loc_401BA5                ; for(i=0;i<loop_cnt;i++)

UPX0:00401C0E                                         ; 第一步就是实现2个UINT的循环左移1

UPX0:00401C10 mov     eax, [esp+10h+arg_0]

UPX0:00401C14 pop     ebp

UPX0:00401C15

UPX0:00401C15 loc_401C15:                             ; CODE XREF: Encode+12↑j

UPX0:00401C15 mov     [eax], esi

UPX0:00401C17 mov     [eax+4], edi

UPX0:00401C1A pop     edi

UPX0:00401C1B pop     esi

UPX0:00401C1C pop     ebx

UPX0:00401C1D retn

UPX0:00401C1D Encode endp

代码解读,直接c代码把

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

// 编码所用

void AllShl(unsigned int* low32, unsigned int* high32, unsigned int left) {

    unsigned int _low32, _high32, lowLeft;

    if (left < 32)

    {

        _low32 = *low32;

        _high32 = *high32;

        lowLeft = _low32 >> (32 - left);

        _high32 = _high32 << left;

        _low32 = _low32 << left;

        _high32 = _high32 | lowLeft;

        *low32 = _low32;

        *high32 = _high32;

    }

}

void Encode(unsigned int* low32, unsigned* high32, unsigned int loop) {

    unsigned int b2,h31,tHigh;

    for (unsigned int i = 0; i < loop; loop--) {

        // 第一步就是循环左移一位,高32位最高位会溢出,所以源程序先保存最高位,然后,补到低32位的最低为

        // 其实就是一个圈

        // 自己实现了一个圈

        h31 = (*high32) >> 31;

        AllShl(low32, high32, 1);

        *low32 = *low32 | h31;

        tHigh = 0;

        b2 = *low32 & 4;            // low32取第2位

        AllShl(&b2, &tHigh, 11);    // 左移11位 + 原来的2位 = 13位

        b2 = b2 ^ (*low32 & 0x2000);// 第二位和第13位亦或

         

        AllShl(&b2, &tHigh, 18);   // 左移18位 + 原来的13位 = 31位

        b2 = b2 ^ (*low32 & 0x80000000);// 第二位和第31位亦或

        AllShl(&b2, &tHigh, 1);

        *low32 = *low32 ^ b2;           // b2 始终等于0

        *high32 = *high32 ^ tHigh;

    }

}

简化后的Encode

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

void Encode(unsigned int* low32, unsigned* high32, unsigned int loop) {

    unsigned int h31, b2, b13, b31;

    for (unsigned int i = 0; i < loop; loop--) {

        // 第一步就是循环左移一位,高32位最高位会溢出,所以源程序先保存最高位,然后,补到低32位的最低为

        // 其实就是一个圈

        // 自己实现了一个圈

        h31 = (*high32) >> 31;

        AllShl(low32, high32, 1);

        *low32 = *low32 | h31;

        // 其实后面的就是取低32位中第 2,13,31位的值进行亦或;然后和高32位最低为进行亦或

        // 简化得到

        b2 = ((*low32) & 4) >> 2;             // 取2位

        b13 = ((*low32) & 0x2000) >> 13;      // 取13位

        b31 = ((*low32) & 0x80000000) >> 31;  // 取31位

         

        b2 = b2 ^ b13 ^ b31;

        *high32 = *high32 ^ b2;

    }

}

简化后其实就2步骤,根据低32位还原高32位;然后循环右移1位

Decode代码可得

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

// 解码所用

void AllShr(unsigned int* low32, unsigned int* high32, unsigned int right) {

    unsigned int _low32, _high32, highRight;

    if (right < 32)

    {

        _low32 = *low32;

        _high32 = *high32;

        highRight = _high32 << (32 - right);

        _high32 = _high32 >> right;

        _low32 = _low32 >> right;

        _low32 = _low32 | highRight;

        *low32 = _low32;

        *high32 = _high32;

    }

}

void Decode(unsigned int* low32, unsigned* high32, unsigned int loop) {

    unsigned int l1, b2, b13, b31;

    for (unsigned int i = 0; i < loop; loop--) {

        // 第一步还原高32位的最低位

        // 还是求低32位的第 2 13 31 位的亦或值,根据亦或特性 还原高32位数值

        b2 = ((*low32) & 4) >> 2;             // 取2位

        b13 = ((*low32) & 0x2000) >> 13;      // 取13位

        b31 = ((*low32) & 0x80000000) >> 31;  // 取31位

        b2 = b2 ^ b13 ^ b31;

        *high32 = *high32 ^ b2;

        // 第二步右旋转1位

        l1 = *low32 & 1;            // 取low32最低位

        AllShr(low32, high32, 1);   // 右移动1位

        l1 = l1 << 31;

        *high32 = *high32 | l1;     // 将l1补到高32位上

    }

}

验证可行性

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

unsigned int a[4];

a[0] = 0x11111111;

a[1] = 0x22222222;

a[2] = 0x33333333;

a[3] = 0x44444444;

printf("Org   : %08lx %08lx %08lx %08lx\n", a[0], a[1], a[2], a[3]);

for (i = 0; i < 3; i++) {

    base = 0x0BADC0DE / (i + 0x50);

    printf("%d loop = %lx\n", i, base);

    Encode(a + i, a + i + 1, base);

}

printf("Encode: %08lx %08lx %08lx %08lx\n", a[0], a[1], a[2], a[3]);

for (i = 2; i >= 0; i--) {

    base = 0x0BADC0DE / (i + 0x50);

    printf("%d loop = %lx\n",i, base);

    Decode(a + i, a + i + 1, base);

}

printf("Decode: %08lx %08lx %08lx %08lx\n", a[0], a[1], a[2], a[3]);

return;

验证结果

1

2

3

4

5

6

7

8

9

Org   : 11111111 22222222 33333333 44444444

0 loop = 255f35

1 loop = 24e918

2 loop = 2475dd

Encode: 647577db 5250c59b 90dc6469 57a10cc3

2 loop = 2475dd

1 loop = 24e918

0 loop = 255f35

Decode: 11111111 22222222 33333333 44444444

keygen

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "md5.h"

char* _strrev(char* s)

{

    char* h = s;

    char* t = s;

    char ch;

    while (*t++) {};

    t--;

    t--;

    while (h < t)

    {

        ch = *h;

        *h++ = *t;

        *t-- = ch;

    }

    return(s);

}

// 解码所用

void AllShr(unsigned int* low32, unsigned int* high32, unsigned int right) {

    unsigned int _low32, _high32, highRight;

    if (right < 32)

    {

        _low32 = *low32;

        _high32 = *high32;

        highRight = _high32 << (32 - right);

        _high32 = _high32 >> right;

        _low32 = _low32 >> right;

        _low32 = _low32 | highRight;

        *low32 = _low32;

        *high32 = _high32;

    }

}

void Decode(unsigned int* low32, unsigned* high32, unsigned int loop) {

    unsigned int l1, b2, b13, b31;

    for (unsigned int i = 0; i < loop; loop--) {

        // 第一步还原高32位的最低位

        // 还是求低32位的第 2 13 31 位的亦或值,根据亦或特性 还原高32位数值

        b2 = ((*low32) & 4) >> 2;             // 取2位

        b13 = ((*low32) & 0x2000) >> 13;      // 取13位

        b31 = ((*low32) & 0x80000000) >> 31;  // 取31位

        b2 = b2 ^ b13 ^ b31;

        *high32 = *high32 ^ b2;

        // 第二步右旋转1位

        l1 = *low32 & 1;            // 取low32最低位

        AllShr(low32, high32, 1);   // 右移动1位

        l1 = l1 << 31;

        *high32 = *high32 | l1;

    }

}

void main()

{

    int i, len,buffLen,lenOffset;

    unsigned char* data;

    char name[128] = "";

    char names[16] = "";

    unsigned int base;

    MD5_CTX ctx;

    printf("pls,input 'name'>");

    scanf("%s", name);

     

    buffLen = strlen(name) * 4 + 1 + 8;       // name + 3次name反转 + 一位字符结束的特殊符号0x80,4字节int + 4字节空白

    buffLen = (buffLen + 0x40) / 0x40 * 0x40; // 64对齐

    lenOffset = buffLen - 8;                  // 最后8字节位置是int=长度<<3

    data = malloc(buffLen);

    memset(data, 0, buffLen);

    printf("name:%s\n", name);

    strcpy(data, name);

    strcpy(names, name);

    _strrev(names);

    for (i = 0; i < 3; i++)

    {

        strcat(data, names); // 因为win10没有注册表项,结果就是这样子

    }

    printf("data:%s\n", data);

    len = strlen(data);

    data[len] = 0x80;

    len += 1;

    *(unsigned int*)(data + lenOffset) = len * 8;

    MD5Init(&ctx);

    for ( i = 0; i < buffLen; i+=64)

    {

        MD5Transform(ctx.state, (unsigned char *)data + i);

    }

     

    printf("md5 : %08lx %08lx %08lx %08lx\n", ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3]);

    ctx.state[0] = ctx.state[0] & 0xffff;

    printf("md5 : %08lx %08lx %08lx %08lx\n", ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3]);

    for (i = 2; i >= 0; i--) {

        base = 0x0BADC0DE / (i + 0x50);

        printf("%d loop = %lx\n", i, base);

        Decode(ctx.state + i, ctx.state + i + 1, base);

    }

    printf("code : %08lx %08lx %08lx %08lx\n", ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3]);

     

    return;

}

几组组NS供验证:

helloworld : 7db37660 ae4c5d05 d2783eea 1d6514f2

pediy.com : b3f21c39 e8ca4483 4146d6f6 5644545b
 

 

  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值