好友
阅读权限35
听众
最后登录1970-1-1
|
solly
发表于 2019-12-20 18:06
本帖最后由 solly 于 2019-12-20 18:18 编辑
160 之 157 - thecodingone.2 是一个命令行形式的 Crackme,通过命令行交互方式输入注册信息,并输出结果。
首先看看文件信息:
节的信息如下:
可以看到,这是一个由 Borland C++ 编译的 Crackme,没有加壳,因此跟踪分析也比较容易。
首先运行一下 Crackme,输出如下图:
需要一个 keyfile 文件验证,我们用 OD 载入 Crackme 程序来分析。载入后如下图所示:
可以看到,这一个调用 C++ 库写成的 Crackme,一开始 Crackme 创建了两个文件流(fstream)。并对流进行初始化,如下图所示:
初始化了两个流,文件名为空(NULL)。按 F8 执行,执行到下图所示位置:
可以看出,Crackme 将自身执行文件作为文件流打开了。同时,还需要打开另一个文件 crack.dat ,这个文件就是 Keyfile,目前不存在,我们先创建一个这样的文件,文件内容随意填,如下图所示:
用本文编辑器生成一个 crack.dat,输入一些内容并保存。
如上图所示,crackme 通过 >> 操作符,读入 crack.dat 的内容,并且是作为一个整数数据读入的。按 F8 执行上面代码,进入下面 keyfile 验证循环,如下图所示:
keyfile 的算法也简单,就是对 Crackme 的执行程序进行累加和的计算并与 crack.dat 的内容进行对比。
如上图所示,[ebp-168] 中是 crack.dat 内容 78787878 ( 十六进制 0x04B23526)。ESI 中是 crackme 计算的累加校验和0xD80A721A,转成 10 进制为 3624563226。这个 3624563226 就是 crack.dat 的正确内容了。
累加校验和的计算方式为:sum = ∑[crackme[ i ] xor (i+1)],其中,i=0,1,2,...n-1,n 为文件长度。如下图所示:
具体代码如下:
[Asm] 纯文本查看 复制代码 00401223 |. EB 2E jmp short 00401253
00401225 |> 8D8D 97FEFFFF /lea ecx, dword ptr [ebp-169] ; char buff
0040122B |. 51 |push ecx
0040122C |. 8D85 14FFFFFF |lea eax, dword ptr [ebp-EC] ; stream_v130 内部成员:输入流, stream_v130.istream
00401232 |. 50 |push eax
00401233 |. E8 24620000 |call istream::get ; 从流(CrackMe自身文件)中读取取一个字节至[ebp-169](istream::get(char &)),流指针后移一字节
00401238 |. 83C4 08 |add esp, 8
0040123B |. 8D95 14FFFFFF |lea edx, dword ptr [ebp-EC]
00401241 |. 52 |push edx
00401242 |. E8 9D620000 |call istream::tellg ; 取流的读取指针位置, eax
00401247 |. 59 |pop ecx ; eax == 1....
00401248 |. 0FBE8D 97FEFFFF |movsx ecx, byte ptr [ebp-169] ; ecx == CRACKME[i], i=0....,最终 ecx = 0xFFFFFFFF, [EBP-169] == 0xFF, 当Eof时返回-1
0040124F |. 33C1 |xor eax, ecx
00401251 |. 03F0 |add esi, eax ; sum += (tellg() ^ CRACKME[i]), 最终 sum = 0xD80A721A
00401253 |> 8B85 D0FEFFFF mov eax, dword ptr [ebp-130] ; eax ===> stream_v130
00401259 |. F640 0C 01 |test byte ptr [eax+C], 1 ; std::basic_ios::eof(), 最终 [eax+c] == 0x00000003, Badbit | Eofbit
0040125D |.^ 74 C6 \je short 00401225
0040125F |. 8D95 D0FEFFFF lea edx, dword ptr [ebp-130]
00401265 |. 52 push edx
00401266 |. E8 39580000 call fstreambase::close ; stream_v130.close()
0040126B |. 59 pop ecx
0040126C |. 3BB5 98FEFFFF cmp esi, dword ptr [ebp-168] ; sum < 0x04B23526 (78787878)Crack.dat 文件保存的数字
00401272 |. 72 08 jb short 0040127C ; 低于跳转, esi = D80A721A = 3624563226 不小于 78787878,不跳转
00401274 |. 3BB5 98FEFFFF cmp esi, dword ptr [ebp-168] ; sum <= 0x04B23526 (78787878)
0040127A |. 76 6B jbe short 004012E7 ; 不高于跳转,因此 Crack.dat 的文件内容为 3624563226 才会跳转到下一步验证,否则退出
如果文件内容校验不对,则输出如下图所示:
显示文件不正确的提示。重新将 crack.dat 的内容改成 3624563226,如下图所示:
重新保存 crack.dat,再次运行到比较累加校验码的位置,如下图所示:
这次就是正确的了。所以 keyfile 文件 crack.dat 的内容就是 3624563226 了。
如果 keyfile 验证通过,则会进入第二个验证,用户名/机构名/序列号 的验证。如下图所示:
首先要求输入用户名称。
如下图所示,第二步验证,需要输入用户名,机构名,序列号等三条数据。
我们在命令行按要求输入相关信息,如下图所示,序列号先随便输入:
输入完后回车,就会进入序列号的验证,如下图所示:
首先判断用户名,机构名的长度,长度都必须大于3,否则会将序列号置”0“,因此,验证也会失败。
长度没有问题,则调用 call dword ptr [ebp-154] (call 00401457)进行序列号验证,该验证函数如下图所示:
最后,输入的序列号(整数)与计算后的序列号进行比较,如下相等则表示序列号正确。而序列号的计算值只与用户名和机构名的第1个字符有关,其它字符没有参与序列号的计算。计算的具体代码如下:
[Asm] 纯文本查看 复制代码 0040146A |. 33FF xor edi, edi ; int sum = 0;
0040146C |. EB 17 jmp short 00401485
0040146E |> 0FBE06 /movsx eax, byte ptr [esi] ; int a = (int)(* pName);
00401471 |. 0FBE13 |movsx edx, byte ptr [ebx] ; int d = (int)(* pOrganization);
00401474 |. F7EA |imul edx
00401476 |. 03F8 |add edi, eax ; sum += a * d;
00401478 |. 53 |push ebx ; /pOrganization ===> "ite123"
00401479 |. E8 AE0A0000 |call strlen ; \eax = strlen(pOrganization)
0040147E |. 59 |pop ecx
0040147F |. 85C0 |test eax, eax ; 无用检查
00401481 |. FE03 |inc byte ptr [ebx] ; Organization[0] ++, 第1个字符的 ASCII 码值加 1
00401483 |. FE06 |inc byte ptr [esi] ; Name[0] ++, 第1个字符的 ASCII 码值加 1
00401485 |> 56 push esi ; /pName ===> "solly"
00401486 |. E8 A10A0000 |call strlen ; \eax = strlen(pName)
0040148B |. 59 |pop ecx
0040148C |. 85C0 |test eax, eax ; 当 Name[0] 递增到 0xFF,再加1溢出为0x00即会退出循环
0040148E |.^ 75 DE \jnz short 0040146E
00401490 |. FF75 10 push dword ptr [ebp+10] ; /pSerial = 0x04B23526 (78787878)
00401493 |. 57 push edi ; |calcSerial = 0x0009E501 (648449)
00401494 |. E8 08000000 call checkfunc ; \thecodin.checkfunc
由上图可以看到,最后是调用 call checkFunc 进行序列号比较的,该函数如下图所示:
就是一个 cmp 指令进行整数比较,相等则显示成功,不相等则显示失败。由上图可以看到,正确的序列号为:0x0009E501(十进制为 648449)。
上图序列不正确,最后显示如下:
表示序列号不正确。
我们重新运行 Crackme,输入正确的序列号,如下图所示:
这次输出如下,表示序列号正确:
另外,这里説明一下,crackme是由 borland c++ 编译的。其在读取文件流时,当到达 eof 时,其 get(char& ch) 取得 ch 为 -1,并且 tellg() 取值还是文件长度,而我用 Dev-C++ 时进行累加校验和计算时,当到达 eof 时,其 get(char& ch) 取得 ch = 0,并且 tellg() 取值是 -1,不再是文件长度。所以,如果用当前的C++编译器编译的程序计算的校验值不对时,可能是这个问题引起的,需要进行修正,修正方式如下:[C++] 纯文本查看 复制代码 //// Dev-C++ 下的修正
crc = crc - (0 ^ (-1)) + ((-1) ^ 96879);
这个在下面的注册机中有体现,注册机源码如下。
[C++] 纯文本查看 复制代码 #include <iostream>
#include <fstream>
#include <string>
#include <string.h>
using namespace std;
int getCrcFile(string filename);
int getSN(char * name, char * organ);
int main(int argc, char** argv) {
string filename = "I:\\Downloads\\crack\\157_thecodingone.2\\thecodingone.2.exe";
int crc = getCrcFile(filename);
cout<<"File CRC: "<<(unsigned)crc<<endl;
char pName[] = "solly";
char pOrgan[] = "ite123";
int sn = getSN(pName, pOrgan);
cout<<"SN: "<<sn<<endl;
return 0;
}
// file-size: 96879, crc: 3624563226
int getCrcFile(string filename) {
int crc = 0;
fstream fs(NULL);
fs.open(filename.c_str(), ios::in | ios::binary);
char c;
int i=0;
do {
fs.get(c);
int p = fs.tellg();
if(++i>=96878) {
cout<<"c = "<<(int)c<<", p = "<<p<<endl;
}
crc += p ^ (int)c;
} while(!fs.eof());
/// Dev-C++ 下的修正
crc = crc - (0 ^ (-1)) + ((-1) ^ 96879);
fs.close();
return crc;
}
int getSN(char * name, char * organ) {
if((strlen(name) < 3) || (strlen(organ) < 3)) {
cout<<"Length of name and organ must be more than 3."<<endl;
return -1;
}
char a = name[0];
char b = organ[0];
int sn = 0;
while(a!=0) {
sn += (int)a * (int)b;
a++, b++;
}
return sn;
}
以上代码由 dev-c++ 调试通过。
内容简单,分析完毕!!!
|
免费评分
-
参与人数 7 | 威望 +1 |
吾爱币 +17 |
热心值 +7 |
收起
理由
|
pk8900
| |
+ 3 |
+ 1 |
用心讨论,共获提升! |
天空藍
| |
+ 1 |
+ 1 |
粉絲拜讀 |
庞晓晓
| |
+ 1 |
+ 1 |
欢迎分析讨论交流,吾爱破解论坛有你更精彩! |
陈世界
| |
+ 1 |
+ 1 |
我很赞同! |
Hmily
| + 1 |
+ 7 |
+ 1 |
感谢发布原创作品,吾爱破解论坛因你更精彩! |
csjwaman
| |
+ 1 |
+ 1 |
感谢发布原创作品,吾爱破解论坛因你更精彩! |
朱朱你堕落了
| |
+ 3 |
+ 1 |
感谢发布原创作品,吾爱破解论坛因你更精彩! |
查看全部评分
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|