首页
社区
课程
招聘
[原创]2024年-KCTF-水泊梁山
发表于: 2024-8-10 17:18 1437

[原创]2024年-KCTF-水泊梁山

2024-8-10 17:18
1437

2024年-KCTF-水泊梁山

签名:水泊梁山.zZhouQing

我设计了一个保护框架,程序的算法较为简单。

汇编层混淆

与内存相关的指令变形

 在之前,我拿到了一份 vmp38 样本,感觉指令变形的样子挺有特色,所以照猫画虎抄了过来。

alt text

基于栈的指令变形

 指令变形主要是基于栈的混淆,学习的样本是 Tencent、滴水壳。效果如上图所示。

ShadowJcc

 将 jcc 指令抹去,通过 hash 等操作直接跳转到 branch/target。不过在本题当中,我并未开启 ShadowJcc 选项。

CFG

 将与代码分支相关的指令做变形。可以看到 IDA 在默认状态下,已经无法正确分析控制流。
alt text

代码层混淆

编译时保护

  可以看到有一些 ObfXX 字样的代码文件,通过宏的方式讲常量隐藏起来。不过我的编译器设置直接优化掉了,在本题中并未体现其特征。
alt text

统一的变量管理

 我将程序的一些关键变量统一地交给 User 管理,防止被暴力搜索引用发现 Flag。

alt text

反调试

 老生常谈的东西,利用如下所示数据或函数进行反调试:

  • NtSetInformationThread/NtQueryInformationThread
  • RDTSC/timeGetTime
  • IsDebuggerPresent

 值得注意的是,反调试结果与 Flags 的计算相结合。

没有添加的反调试

 在 ReadMe.md 的目录下,存在着 AntiDbgSigCollect.py 文件,这是我一开始准备用来辅助特征检测的脚本,不过后来并未打算添加。因为我一开始是写来针对 CpuDbg 师傅的,哈哈。
alt text

程序验证算法:

用到如下内容:

  • 查表移位
  • RC6
  • DES
  • CRC32
  • MD5

程序界面:

 正常登录时如图所示:

alt text

 被检测到反调试时如图所示:
alt text

关于程序的具体设计

 请看 WriteUP 目录,很抱歉,我还没有写完,只是这俩天随便写了点就干其他事情去了。会在赛期之内写好的。


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

最后于 2024-8-20 12:01 被kanxue编辑 ,原因:
上传的附件:
收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 47147
活跃值: (20445)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
2
多解了,见QQ消息
2024-8-11 09:13
0
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3

2024-KCTF-水泊梁山-修改记录.md

签名:水泊梁山.zZhouQing

第一次修改

 雪叔在测试的时候,发现程序出现多解。原因是题目中的 IO 输入是调用了 std::cin 这个函数。这个函数会截取空格,导致后面的字符不出现了。

// input: 123456<space>78
// output: 123456

std::cin << curUserSerial;
----修改成----------------------
std::getline(std::cin, curUserSerial);

第二次修改

 雪叔在测试的时候,发现程序出现下图的情况:

 其实这是我留了一个坑,利用 kctfer 没有 KCTF 对应的 Serial 这一特点,在程序走向错误分支的时候,程序会发生栈溢出。在这道题当中,若要定位栈溢出发生的位置,一般要 trace 50 万行汇编指令。如果 kctfer 试图探究为什么会栈溢出,那就进了一个大坑了。因为程序必然发生栈溢出,hiahia。

 不过这样子违规了。

C)规则限制
干净环境中,当前主流硬件配置环境下,10秒内出提示且不能虚假提示。

 通过对 Serial 的输入长度加以限制,并输出相应的提示。也就不违规了。

第三次修改

 对特定的密码学算法进行了基本块的分割或者说是隐藏。

总结

 大概就是经过了三次修改这个样子,这是我第一次参加 KCTF,犯了很多错误。感谢 kanxue 前辈的提醒。赛期似乎是 4 还是 7 天, 我会根据情况给坛友适当的提醒。如利用了什么算法,算法的网络链接,都具有什么特征,甚至在赛期内将混淆的源码公布。

 毕竟我的技术就是从论坛学来的。

最后于 2024-8-12 17:10 被zZhouQing编辑 ,原因:
2024-8-12 16:44
0
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4

2024年KCTF水泊梁山-混淆

签名:水泊梁山.zZhouQing

基本块的构建

 一个基本块被引用多少次,就会相应的构建多少个基本块。(或者说是基本块的复制)

// 这串代码中,会构建 4 次基本块。
jmp_1(LABEL_1);
jmp_2(LABEL_1);
jmp_3(LABEL_1);
jmp_4(LABEL_1);

LABEL_1:
nop();
nop();
nop();
nop();

花指令

 印象里花指令的模板源是抄的 OllyDbg 的插件 DeJunk.dll。(似乎这个插件又集成了其他插件的模板,很强大)

;Originary Write by ljtt
S = 9C6A??730BEB02????E806000000????73F7????83C404EB02????FF0C247101??79E07A01??83C4049DEB01??
S = 9C720AEB01??E805000000????72F4??83C4049DEB01??
S = 72037301??

 不过遗憾的是,花指令功能似乎与其他功能发生了冲突,我并没有开启。

指令变形

 变形的基础是栈,我們知道,vmp 38 引入了内存的概念,在内存上做文章。出現形式如下:

push [addr]
push [addr]
mnemonic r,rm
mnemonic r,imm
pop [addr+rd_offset]
pop [addr+rd_offset]

 我感觉其挺有特色,抄了过来。(同时也借鉴了 x_tvm.exe)

ShadowJcc

 一般地情況下,基本塊若要實現跳轉,需要經過如下過程。

cmp reg,const_v\cmp [mem],const_v\cmp [rm],const_v
jcc branch_target

 基本思路便是混淆 const_v,混淆 branch_target,各位請看實現過程。

 以 Cmp_rm32_imm8 類型指令爲例,將 Cmp_rm32_imm8 與 Je_rel32_32 倆條指令替換成如下形式:

// 注:
// [mem] 存儲 const_v
// this_ins_next_2_ip je 指令對應 IP 的下倆條指令地址
xor dword [mem],reg 
cmp dword [mem],hash_branch_target
je this_ins_next_2_ip
jmp [mem]

 此時,KCTFEr 若要逆向循環次數,變需要對 const_v 進行逆向,或進行統計記錄分析,有著不錯的反調試效果。

 不过遗憾的是,ShadowJcc 功能似乎与其他功能发生了冲突,我并没有开启。

Visual Machine

 实际上小菜还逆向了 Safengine24 ,给它抄了一下,不过没有合并到 2024年KCTF水泊梁山 的代码里。这次的 KCTF 奖品力度有点低,放在下次~

 当然,我也得注意加强自身的代码和安全能力,这次的题目 花指令ShadowJcc 没有增加上去,很是遗憾。

指令变形代码的缺陷

 指令变形的模板是我随便想的,没有依据 eflags 进行设计,程序执行流程可能出错。这可能从理论上说明了,在一定程度上的验证算法层面可能有唯一解,但添加了指令变形这一影响因素,可能存在多解。

 要解决这一问题,我想我需要做一张 eflags 的真值表,基于 eflags 真值表来编写基于栈的混淆。这一基础性的工作完成了,我想也就可以肆无忌惮地套用 具有一定周期性的理论 或是 布尔代数 来混淆。

 如果完成了这一基础性工作,我想也就可以用来证明 程序验证算法 是否有可能出现 因 eflags 导致的多解 了。

 在题目当中,我只测试了 KCTFsha256(file,16) 是能正常工作的,但测试并不严谨。倘若坛友感兴趣,欢迎讨论交流。

存在大量的内存空间没有利用

 这次的题目,经过混淆后的执行代码就有至少 1690257 字节未利用。这样的效果实在是令人难以接受。

通过压缩测试混淆

 在发现混淆后的效果令人难以接受后,发现将程序进行压缩能有不错的效果。利用 upx 加壳,印象里是将 10mb 压缩到了 1mb,这可能说明了我的混淆仅仅只有 1mb 的量,或者说我的混淆 熵值 太低,安全性是不够的。

反思

 这说明了混淆至少需要改进俩个地方:

  • 变形后的熵值(需要多样化的变形)
  • 增大内存空间的利用率

 这也就需要我设计一个计算一定范围的代码块的熵值算法。我想,可以从 Nisy 前辈的 Baymax toOls 入手。

 混淆至少需要修复一个地方:

  • 变形代码影响的 eflag 与原指令保持一致

 当然,我会保留原有的混淆形式,通过宏的方式进行管理,如果你认为当前的函数对执行流程不用过多在意,那就用吧!

闲谈

 现在的论坛相对于之前似乎冷清了不少,人情味变少了,争吵变多了。

 这样的话实在是太难听,“据教育部最新公布的数据显示,到2027年,我国网络安全人员缺口将达327万”,国家人才缺口这么大,我想,大家应该沉下心,和谐讨论,毕竟 “善语一句三冬暖,恶语相向六月寒” 嘛。

”"中国逆向现在什么水平,就这么几个人,你肉丝什么的都在搞培训,他能搞吗?搞不了!没这个能力知道吗? "“再下去要输吾爱了,吾爱输完输飘云阁,再输学破解,接下来没人输了。”

 论坛有这样的一个帖子,"关于我逆了一个号称VT读取物理内存条的驱动,最后发现他只个IO这件事",似乎楼主仅是逆向了 免费版 的 demo,这样的标题不太合适。

 似乎论坛的老一辈都成家立业了,在学习的过程中,我遇到了 xdbgcpudbgnisy 等大侠,他们说话很有意思。cpudbg 老师傅的头像是个妹子,当然,nisy 叔的头像也是,这是一个头像用了十几年么。海风月影 大叔的头像也很好玩,是只小老鼠,带哭的,甚是可爱。

 论坛防守组截至的时候是 10 号,我很开心,七夕的这一天,我成年了。

2024-8-20 12:06
0
雪    币: 256
活跃值: (674)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5

2024-KCTF-水泊梁山-算法验证.md

签名:水泊梁山.zZhouQing

算法验证共有四组。

CheckSerial

 CheckSerial,这个是之前在论坛看到的一个 tencent 样本,做了点分析。今天拿过来魔改了一下。这个面试题似乎有好几个版本,这份是较难的,主要考察的是 Windows 系统原理,和算法无关。

__forceinline std::string DeCheckSerial1(std::string serial_1) {
    unsigned char buffer[32];
    hexString2Bytes(serial_1, buffer);
    unsigned char _tmp[16] = {};
    unsigned char _tmp2[16] = {};
    RC6_DE((uint32_t*)_tmp, (uint32_t*)&buffer);
    RC6_DE((uint32_t*)_tmp2, (uint32_t*)&buffer[16]);
    char fpw[32] = {};
    for (size_t i = 0; i < 16; i++)
    {
        fpw[i] = _tmp[i];
    }
    for (size_t i = 0; i < 16; i++)
    {
        fpw[i + 16] = _tmp2[i];
    }
    return fpw;
}

__forceinline int CheckSerial()
{

    auto un = user.GetData<std::string>(userName);
    auto pw = user.GetData<std::string>(userSerial);
    
    if (pw.size() < ObfInt2(24))
    {
        return user.GetData<int>(SerialFailFlag2);
    }
    user.SetData<int>(gloablConstV, ObfInt2(0x506) ^ user.GetData<int>(KeyGenFlag));


    unsigned char uN2 [9];
    getUn2((unsigned char*)un.c_str(), uN2);
    int constV = user.GetData<int>(gloablConstV);
    *(int*)((int*)uN2) ^= constV;
    *(int*)((int*)uN2 + 1) ^= constV;
    char flag1, flag2, flag3;
    unsigned char* serial = new unsigned char[ObfInt2(33)];
    serial[ObfInt2(32)] = {};
    setMemSig(serial,0,32);
    //setMemSig(serial, 0, 32);
    for (size_t i = 0; i != 8; i++)
    {
        flag1 = ((uN2[i] & ObfInt2(0X30)) + (((uN2[i] & ObfInt2(0X50)) >> ObfInt2(0X8)) & ObfInt2(0X4))) >> ObfInt2(0X5);
        flag2 = (uN2[i] & ObfInt2(0X10)) + (((uN2[i] & ObfInt2(0X6)) >> ObfInt2(0X7)) & ObfInt2(0X3)) >> ObfInt2(0X2);
        flag3 = uN2[i] & ObfInt2(0X4);

        int flag4 = i % 3;
        if (flag4 == 2)
        {
            serial[i * 3] = t5_864[flag3];
            serial[i * 3 + 1] = t6_83c[flag1];
            serial[i * 3 + 2] = t7_874[flag2];
        }

        if (flag4 == 1)
        {
            serial[i * 3] = t3_834[flag1];
            serial[i * 3 + 1] = t4_87c[flag2];
            serial[i * 3 + 2] = t5_864[flag3];
        }

        if (flag4 == 0)
        {
            serial[i * 3] = t3_834[flag2];
            serial[i * 3 + 1] = t4_87c[flag3];
            serial[i * 3 + 2] = t5_864[flag1];
        }
    }
    
    for (int i = 0; i != 24; i++)
    {

        auto npw = DeCheckSerial1(pw);
        if (serial[i] != npw[i])
        {
            user.SetData<int>(gloablSerialFlag, ObfInt2(0x1314));
            user.SetData<int>(KeyGenFlag, ObfInt2(0x21));
            return user.GetData<int>(SerialFailFlag);
        }
    }
    user.SetData<int>(gloablSerialFlag, ObfInt2(0));
    user.SetData<int>(SerialSuccessFlag, ObfInt2(0x999));
    return user.GetData<int>(SerialSuccessFlag);
}

CheckSerial2

  这部分主要用来反调试,同时 serial_2 参加后续的算法验证。

__forceinline int CheckSerial2(std::string un,std::string serial)
{
    SBLS_ANTI_TIME_RDTSC();
    auto serial_1 = serial.substr(0, 32 * 2);
    SBLS_ANTI_TIME_RDTSC();

    auto serial_2 = EnCheckSerial_2(un,serial_1);
    SBLS_ANTI_TIME_RDTSC();

    auto cur_serial_2 = serial.substr(32 * 2, 8);
    SBLS_ANTI_TIME_RDTSC();

    SBLS_ANTI_TIME_RDTSC();
    if (DeCheckSerial_2(cur_serial_2,serial_1) == DeCheckSerial_2(serial_2, serial_1))
    {
        return 0;
    }
    SBLS_ANTI_TIME_RDTSC();
    return -1;
}

CheckSerial3

 算法流程与 CheckSerial1 类似,修改了表的位置以及讲表的部分数据在特定时候还原。

__forceinline int CheckSerial3(std::string _un,std::string _serial)
{

	unsigned char t[0x0010] =
	{
	0xf7, 0xff, 0xff, 0x89, 0x8d, 0x4c, 0xf7, 0xff, 0xff, 0xc7, 0x85, 0x48, 0xf7, 0xff, 0xff, 0x14
	};


	unsigned char t2[0x0010] =
	{
	0x07, 0x82, 0x19, 0xe8, 0x1f, 0xfe, 0xff, 0xff, 0x0f, 0xb6, 0xd0, 0x85, 0xd2, 0x74, 0x05, 0xe9
	};

	unsigned char t3_834[0x0040] =
	{
	0x52 ^ 3, 0x51 ^ 3, 0x53 ^ 3, 0x54 ^3, 0x55 ^ 3, 0x57, 0x56, 0x5a, 0x59, 0x58, 0x00, 0x00, 0x40, 0xed, 0x9f, 0xf5,
	0x26, 0x3a, 0x6f, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};

	unsigned char t4_87c[0x00B0] =
	{
	0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
	0x79, 0x7a, 0x6e, 0x69, 0xc9, 0x1b, 0x40, 0x00, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
	0x48, 0x49, 0x18, 0x00, 0xa0, 0xf0, 0x18, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
	0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
	0x59, 0x5a, 0x00, 0x00, 0x40, 0xed, 0x9f, 0xf5, 0x26, 0x3a, 0x6f, 0x8f, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};

	unsigned char t5_864[0x0090] =
	{
	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x18, 0x00, 0xa0, 0xf0, 0x18, 0x00,
	0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
	0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x40, 0xed, 0x9f, 0xf5,
	0x26, 0x3a, 0x6f, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};

	unsigned char t6_83c[0x001E] =
	{
	0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
	0x59, 0x5A, 0x7F, 0x00, 0xF6, 0x9A, 0xE2, 0xF7, 0x9B, 0x50, 0x09, 0x80, 0x00, 0x00
	};

	unsigned char t7_874[0x003C] =
	{
	0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x19, 0x00, 0xC9, 0x1B, 0x40, 0x00,
	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C
	};

	unsigned char uN2[9];
	//std::cout << "Un2:\t\n" << user.GetData<int>(KeyGenFlag);
	getUn3((unsigned char*)_un.c_str(), uN2);
	int constV = 0x520 ^ (user.GetData<int>(KeyGenFlag) - ObfInt2(2));
	*(int*)((int*)uN2) ^= constV;
	*(int*)((int*)uN2 + 1) ^= constV;
	char flag1, flag2, flag3;
	unsigned char* serial = new unsigned char[ObfInt2(33)];
	serial[ObfInt2(32)] = {};
	setMemSig(serial, 0, 32);
	//setMemSig(serial, 0, 32);

	if (user.GetData<int>(KeyGenFlag) != 2)
	{

		for (size_t i = 0; i != 8; i++)
		{
			flag1 = ((uN2[i] & ObfInt2(0x20)) + (((uN2[i] & ObfInt2(0x30)) >> ObfInt2(0x40)) & ObfInt2(0X4))) >> ObfInt2(0X5);
			flag2 = (uN2[i] & ObfInt2(0x6)) + (((uN2[i] & ObfInt2(0x5)) >> ObfInt2(0X7)) & ObfInt2(0X3)) >> ObfInt2(0X2);
			flag3 = uN2[i] & ObfInt2(0X4);

			int flag4 = i % 3;
			if (flag4 == 2)
			{
				serial[i * 3] = t5_864[flag2];
				serial[i * 3 + 1] = t6_83c[flag1];
				serial[i * 3 + 2] = t7_874[flag3];
			}

			if (flag4 == 1)
			{
				serial[i * 3] = t3_834[flag2];
				serial[i * 3 + 1] = t4_87c[flag3];
				serial[i * 3 + 2] = t5_864[flag1];
			}

			if (flag4 == 0)
			{
				if (flag3 == 0x4 || flag3 == 0x3 || flag3 == 0x2 || flag3 == 0x1 || flag3 == 0x0)
				{
					serial[i * 3] = t3_834[flag3] ^ 3;
				}
				else
				{
					serial[i * 3] = t3_834[flag3];
				}
				serial[i * 3 + 1] = t4_87c[flag2];
				serial[i * 3 + 2] = t5_864[flag1];
			}
		}

		for (int i = 0; i != 24; i++)
		{
			auto serial_3 = _serial.substr(32 * 2 + 8, 32 * 2);

			auto npw = DeCheckSerial3(serial_3);
			if (serial[i] != npw[i])
			{
				//user.SetData<int>(KeyGenFlag, user.GetData<int>(KeyGenFlag) + ObfInt2(0X7));
				return user.GetData<int>(SerialFailFlag);
			}
		}
		return user.GetData<int>(SerialFailFlag2);
	}
	else
	{

		for (size_t i = 0; i != 8; i++)
		{
			flag1 = ((uN2[i] & ObfInt2(0x20)) + (((uN2[i] & ObfInt2(0x30)) >> ObfInt2(0x40)) & ObfInt2(0X4))) >> ObfInt2(0X5);
			flag2 = (uN2[i] & ObfInt2(0x6)) + (((uN2[i] & ObfInt2(0x5)) >> ObfInt2(0X7)) & ObfInt2(0X3)) >> ObfInt2(0X2);
			flag3 = uN2[i] & ObfInt2(0X4);

			int flag4 = i % 3;
			if (flag4 == 2)
			{
				serial[i * 3] = t5_864[flag2];
				serial[i * 3 + 1] = t6_83c[flag1];
				serial[i * 3 + 2] = t7_874[flag3];
			}

			if (flag4 == 1)
			{
				serial[i * 3] = t3_834[flag2];
				serial[i * 3 + 1] = t4_87c[flag3];
				serial[i * 3 + 2] = t5_864[flag1];
			}

			if (flag4 == 0)
			{
				if (flag3 == 0x4 || flag3 == 0x3 || flag3 == 0x2 || flag3 == 0x1 || flag3 == 0x0)
				{
					serial[i * 3] = t3_834[flag3] ^ 3;
				}
				else
				{
					serial[i * 3] = t3_834[flag3];
				}
				serial[i * 3 + 1] = t4_87c[flag2];
				serial[i * 3 + 2] = t5_864[flag1];
			}
		}

		for (int i = 0; i != 24; i++)
		{
			auto serial_3 = _serial.substr(32 * 2 + 8, 32 * 2);

			auto npw = DeCheckSerial3(serial_3);
			if (serial[i] != npw[i])
			{
				user.SetData<int>(KeyGenFlag, user.GetData<int>(KeyGenFlag) + ObfInt2(0X7));
				return user.GetData<int>(SerialFailFlag);
			}
		}
		return user.GetData<int>(SerialSuccessFlag);
	}


}

CheckSerial4

  将用户名进行 hash 得到 un_md5,crc32(un_md5) 的值为公式 f(x) = e(y) 中的 e(y)。

__forceinline int CheckSerial4(std::string un,std::string serial) 
{
	auto cur_serial_2 = serial.substr(32 * 2, 8);
	auto cur_serial_4 = serial.substr(32 * 2 + 8 + 32 * 2,8);
	auto cur_serial_5 = serial.substr(32 * 2 + 8 + 32 * 2 + 8,serial.size());

	auto un_md5 = md5sum6(un.c_str());

	auto un_crc32 = CRC32((unsigned char*)un_md5.c_str(), un.size());
	

	int cur_serial_2_crc = CRC32((unsigned char*)cur_serial_2.c_str(), cur_serial_2.size());
	if (CheckSerial2(un, serial)!=0)
	{
		return user.GetData<int>(SerialFailFlag);
	}
	string serial_4 = bytes2HexString((unsigned char*)&cur_serial_2_crc, 4);
	
	if (getMemCmp((unsigned char*)cur_serial_4.c_str(), (unsigned char*)serial_4.c_str(), 8) == 0)
	{
		unsigned char cur_serial_5_char[8];
		/*std::cout << "cur_serial_5:" << std::endl;
		std::cout << cur_serial_5 << std::endl;*/
		hexString2Bytes(cur_serial_5, cur_serial_5_char);
		bitset<64> cipher = DES_charTobitset((const char*)cur_serial_5_char);
		
		des_key = DES_charTobitset(cur_serial_4.c_str());
		bitset<64> temp_plain = DES_decrypt(cipher);
		
		unsigned char de_cipher[8];
		DES_bitsetToChar(temp_plain,(char*)de_cipher);


		auto un_crc32_bit = DES_charTobitset(bytes2HexString((unsigned char*)&un_crc32, 4).c_str());


		if (un_crc32_bit == temp_plain)
		{
			return user.GetData<int>(SerialSuccessFlag);
		}

	}
	return user.GetData<int>(SerialFailFlag);
}

注册机

 这部分内容,各位大侠看 KeyGen 就好了,不在此赘述。

最后于 2024-8-20 12:21 被zZhouQing编辑 ,原因:
2024-8-20 12:20
0
雪    币: 8175
活跃值: (6399)
能力值: ( LV12,RANK:207 )
在线值:
发帖
回帖
粉丝
6
学习了
2024-8-20 12:56
0
雪    币: 107
活跃值: (172)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
7
后续技术贴跟进讲解
2024-8-20 15:34
0
游客
登录 | 注册 方可回帖
返回
//