吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2482|回复: 34
收起左侧

[原创] 010 Editor 注册机

  [复制链接]
Evan422 发表于 2026-6-17 10:40

样本版本:v16.0.4(64位的)

CSDN真挺傻逼的,稍微有一点价值的文章都给你上付费,看不惯这种,所以自己动手搞搞


1. 定位:从验证错误提示进行切入

他这个没有壳,字符串也没有被抹掉,难度较低,授权失败时弹的是 "Invalid name or license ...", 对应的 ASCII 字面量:

地址 说明
字符串 aInvalidNameOrL 0x1407C3580 .rdata,RVA 0x7C3580
唯一引用 0x1402B2DC7 lea rdx, aInvalidNameOrL,位于 sub_1402B24F0

运行时交叉验证过:该串的实际地址 0x7FF6C55E3580 减掉 ASLR 基址 0x7FF6C4E20000 = 0x7C3580,和 IDA 里的 RVA 能够对上。


2. OK 按钮处理函数 sub_1402B24F0 的整体流程

把 UI 构造、异常清理那些噪音去掉,关键骨架是这样的:

name    = a1[24]        // 第一个 QLineEdit
license = a1[26]        // 第二个 QLineEdit
  // 一组输入合法性检查:空值 / 首尾空白 / 长度,只影响提示,不影响算法

sub_1400014AB(mgr, name)        // 把 name 存进授权管理器单例 qword_140FFADB8
sub_14000B9B0(mgr, license)     // 把 license 预处理后存进 mgr+48,长度存 mgr+64

n231 = sub_140003D64(mgr, 17, 20300)    // 主判定,返回状态码
n524 = sub_1400088A5(mgr, 17, 20300)    // 次判定(内部复用主判定),返回状态码

if (n231 != 231 && mgr+124 != 0)        // 条件性联网(二级/激活),不参与主判定
    sub_14000EA57(...)                  //   连 sweetscape.com

// 状态码分支(注意 n524 优先):
if      (n524 == 219)                 -> "License activated ... Thank you for purchasing 010 Editor!"   // 成功
else if (n524 == 237 || n524 == 524)  -> "license is for an earlier version"
else if (n231 != 147)                 -> "Invalid name or license ..."     // 失败
else if (n524 != 113)                 -> "trial period is already over"
else                                  -> "trial period has been extended"

// 成功后:
sub_140007789(mgr)              // 把 license 写进注册表/文件

两个传入的常量 1720300 一直跟着判定走:17 是当前主版本号(版本上限校验要用),20300 是个上限基准,但是我们只关心 0x9C 类型路径里不直接参与判定。

核心:授权是否通过完全由 n231 / n524 两个码决定,而这两个码是上面两个本地函数算出来的,没有走网络请求。(所以其实内存patch也行,但是我觉得不方便)


3. license 字符串的格式与解码

sub_14000B9B0 是 thunk,真身 sub_14043F090,它先调 sub_140008913(真身 sub_14043F0E0)做一次字符预处理,再把结果存到 mgr+48(QString),长度存 mgr+64

3.1 预处理:O/l 别名(sub_14043F0E0)

很简单,逐字符替换:

'O' (79) 或 'o' (111)  ->  '0' (48)
'l' (108)              ->  '1' (49)

3.2 取字节:sub_14000E214sub_14043E820

判定函数一上来调它,把 license 字符串拆成一个字节数组(填进调用者栈上的 10 字节缓冲 v39..v48)。逻辑:

  • 先把存好的字符串(mgr+48)复制出来,读其长度 n24 = mgr+64
  • 只接受长度 19 或 24,且固定位置必须是 -:
    • 19:'-' 在下标 4、9、14 → 4 组、解出 8 字节
    • 24:再加下标 19 的 '-' → 5 组、解出 10 字节
  • 每两个字符拼成一个字节:byte = nibble(hi) * 16 + nibble(lo)

也就是格式是 AAAA-BBBB-CCCC-DDDD(19)或 AAAA-BBBB-CCCC-DDDD-EEEE(24),本质就是带连字符的十六进制串。

字符到半字节的映射 sub_14000B2DAsub_14043E7D0:

'0'..'9'        -> 0..9
'a'..'f' / 'A'..'F' -> 10..15      ('a'-'z' 实际返回 c-87,'A'-'Z' 返回 c-55,
                                     超过 f 的字母会给出 >15 的"半字节",属未定义用法)
'O'/'o'         -> 0    (预处理后其实已是 '0')
'l'             -> 1    (同上)
其它            -> 0

还原时只用 0-9A-F 就行,标准十六进制。


4. 主判定 sub_140003D64sub_14043D0E0

sub_140003D64 是 thunk,真身 sub_14043D0E0。它干三件事:查母钥匙表 → 按类型字节分派算法 → 比对校验和。

4.1 母钥匙表

函数开头先拿 name 去撞两张内置表:

  • off_140E1C5C0 ~ unk_140E1C5D0:一组特殊用户名,QString::operator== 命中任意一个直接 return 231(在 §2 的码表里 231 不等于 147,但这条是判定内部的"有效"出口,配合次判定走成功)。
  • unk_140E1C5D1 ~ byte_140E1C5E9:每条 12 字节 = (用户名头 2 个字符的大写)+(10 字节 license 序列)。比对方式:name 头两个字符 toUpper 后与前 2 字节相等,且解码出的 10 字节逆序逐字节等于后 10 字节,命中即 return 231

注册机用不上它(写出来只是想说有时候商业软件感觉也就是个草台班子,想起之前看到的一篇关于医院小程序病人数据直接明文返回没有任何脱敏我就想笑)

4.2 类型字节分派(关注 0x9C)

撞表没中就进 switch (类型字节)。三个分支:0x9C(主流永久授权)、0xFC(另一种,会走 sub_14000B0FA 二次变换)、0xAC(带 mgr+132 计数)。注册机我选走最常见的 0x9C0x9C 分支完整逻辑:

// b0..b7 已由 §3.2 解码到 v39,v40,v41,v42(=0x9C),n5999655_1,v44,v45,v46
v20  = (uint8)(v44 ^ v41) + ((uint8)(v46 ^ v40) << 8);      // 16 位参数
mgr+108 = (uint8) ad76(v45 ^ v39);                          // 版本上限 n2
v21  = c5b(v20);                                            // 另一参数,模 11
mgr+112 = v21;
n2   = mgr+108;

if (n2 != 0 && (uint32)(v21 - 1) <= 0x3E7) {               // 要求 1 <= v21 <= 1000
    n255 = 0;
    if (n2 < 2) n255 = mgr+108;                            // n2>=2 时 n255 恒为 0

    utf8 = name.toUtf8();
    chk  = checksum(utf8, /*flag*/ (v42 != 0xFC), n255, v21);   // 0x9C -> flag=1

    if (   n5999655_1 == (uint8)(chk      )                // b4 == chk[0]
        && v44        == (uint8)(chk >>  8)                // b5 == chk[1]
        && v45        == (uint8)(chk >> 16)                // b6 == chk[2]
        && v46        == (uint8)(chk >> 24) )              // b7 == chk[3]
    {
        if (v42 == 0x9C) {
            if (version_arg /*=17*/ > mgr+108) return 78;  // "earlier version"
            else                               return 45;  // 成功
        }
        ...
    }
    return 231;
}
return 231;

0x9C 要过校验需要同时满足:

  1. 版本上限够大:n2 = ad76(b6 ^ b0) 必须 >= 17(传入的当前版本号)。n2 >= 2n255 恒为 0。
  2. 参数 v21 合法:v21 = c5b(v20) 落在 [1, 1000],其中 v20 = (b5 ^ b2) | ((b7 ^ b1) << 8)
  3. 校验和逐字节相等:对 name 算出的 4 字节校验和,正好等于 license 里的 b4 b5 b6 b7

b5 b6 b7 既是校验和的目标,又通过第 1、2 条参与 n2v20 的计算——看着是循环依赖,其实不是,因为 b0 b1 b2 是三个完全自由的字节,可以反过来"吸收"掉 b5 b6 b7 的取值。

4.3 两个小变换

都短到可以直接抄进注册机:

// sub_14000AD76 -> sub_14043C060 :版本上限,字节 -> 字节,是个双射(输出覆盖 0..255)
uint8 ad76(uint8 b) {
    return (uint8)(((b ^ 0x18) + 61) ^ 0xA7);
}

// sub_140008C5B -> sub_14043BFD0 :参数,16 位 -> 值,不被 11 整除就作废
uint16 c5b(uint16 x) {
    uint16 v = (uint16)(((x ^ 0x7892) + 19760)) ^ 0x3421;
    return (v % 11) ? 0 : (uint16)(v / 11);
}

因为 ad76 是双射、值域是完整的 0–255,所以版本上限想给多大给多大(我取了最大值 255,等于对所有版本永久有效)。

4.4 校验和 sub_14000C9AFsub_14043C0B0(核心)

这是整套算法的核心,它吃 4 个参数:name 的 UTF-8 指针、一个 flag(0x9C 时为 1)、两个字节参数 a3(= n255)和 a4(= v21),返回 32 位值,取其 4 个字节小端去和 license 比。算法是基于一张 256 项 uint32 常量表 dword_140E1C0F0 的逐字符累加,带几个步进各异的游标:

uint32 checksum(const char *name, int flag, uint8 a3, uint8 a4) {
    const uint32 *T = dword_140E1C0F0;   // 256 项
    uint32 v5 = 0;                        // 累加器
    uint8  g9  = 0;                       // 游标,步进 +19
    uint8  g10 = (uint8)(15 * a4);        // 游标,步进 +13   <- a4 = v21 低字节
    uint8  g11 = 0;                       // 游标,步进 +7(仅 flag==0 用)
    uint8  g12 = (uint8)(17 * a3);        // 游标,步进 +9    <- a3 = n255 低字节

    for (const char *p = name; *p; ++p) {
        uint8 cu = toupper((uint8)*p);                 // C locale,逐字节大写
        uint8 ia = (uint8)(cu + (flag ? 13 : 63));
        uint8 ib = (uint8)(cu + (flag ? 47 : 23));
        uint8 ig = flag ? g9 : g11;

        uint32 t  = (v5 + T[cu]) & 0xFFFFFFFF;          // v17
        uint32 x  = (T[ia] ^ t) & 0xFFFFFFFF;           // v18
        v5 = (T[g10] + T[g12] + T[ig] + T[ib] * x) & 0xFFFFFFFF;

        g12 += 9;  g10 += 13;  g9 += 19;  g11 += 7;     // 全部按 uint8 回绕
    }
    return v5;
}

这里有几个容易踩坑的实现细节,需要注意一下:

  • 所有游标都是 uint8,自增后按 256 回绕;15 * a417 * a3 也截到低 8 位。
  • v532 位无符号,每一步乘加都对 2^32 取模;表项当无符号 32 位用即可(乘法对低 32 位而言有无符号一致)。
  • 这一轮的 v5 用的是自增之前g9/g10/g12,游标自增只影响下一轮(反编译里指针在自增语句之前已取好,别搞反顺序)。
  • flag0x9C 下恒为 1,所以走 +13 / +47、用 g9 那条;g11/另一组偏移是给别的类型字节用的。
  • toupper 按 C locale,只动 ASCII 的 a-z;name 里出现非 ASCII 字节时各平台 toupper 可能不同,稳妥起见注册机只支持 ASCII 用户名(这也是它实际接受的范围)。

a30x9C 路径下恒为 0(因为 n2 >= 2),所以 g12 起点就是 0;a4 = v21 & 0xFF,只有 v21 的低字节进校验和。


5. 次判定 / 成功码 sub_1400088A5sub_14043DC50

if (mgr+124 != 0) return 275;                      // 已激活/特殊状态旁路
v6 = sub_140003D64(mgr, 17, 20300);                // 复用主判定
switch (v6) {
  case 45:  return 219;                            // -> "License activated"(成功)
  case 78:  n23 = sub_14000C8AB(mgr, 17);          // 旧版本
            return (n23 != 23) ? 237 : 524;
  case 231: return 375;
  default:  // 含主判定返回 147(0xFC 那条)
            n23 = sub_14000C8AB(mgr, 17);
            if (n23 == 23)  return 113;
            if (n23 == 42)  return (sub_14000EC3C(mgr) == 419) ? 249 : 375;
            if (n23 == 312) return (sub_14000EC3C(mgr) == 419) ? 249 : 47;
            return 375;                            // 试用相关码
}

整张码表里只有主判定返回 45 才映射到 219 "License activated",而能产出 45 的就只有 0x9C(版本够)和 0xAC(等级 >= 20300)两条路径。0xFC 给出的 147 落进 default,只会得到试用码。mgr+124 在正常激活流程里是 0,所以那条 275 旁路和 OK 处理函数里的联网分支都不触发。


6. 实现注册机算法

import struct

# ---- 校验和常量表 dword_140E1C0F0 (0x140E1C0F0, 256 个 uint32, 小端) ----
_TABLE_RAW = (
    "b8 44 cb 39 67 4f 75 23 11 72 01 5f da 24 bb 3e c6 07 17 35 4b 77 f9 63 88 72 82 17 21 48 e7 0f"
    " 0f 67 5f 5b e8 5a 31 48 69 77 5b 78 47 15 7a 2b 92 12 d1 38 32 1b a1 42 44 22 33 35 60 7b 43 77"
    " 10 3b ab 1e 00 00 81 53 ae 12 02 1d a8 77 03 6f 92 30 c0 43 8e 0a 3c 2d bf 0c 95 62 fa 6f f0 30"
    " e0 10 f7 34 fb 17 f4 28 95 2f 0d 35 5a 1d 36 5a 0b 06 cc 15 cc 13 fd 0a cf 3b 60 28 6b 06 71 33"
    " e4 14 cd 30 67 3a 5d 17 13 6a d6 6d f9 09 34 2d 82 7b 1e 58 99 6b 52 76 88 51 8d 5c 71 79 85 2c"
    " c0 1f f5 15 11 0d cc 68 5c 5e f5 49 64 43 5e 27 bc 0d 1e 2d e3 7c ee 4c 40 58 55 32 08 2e 2e 11"
    " 5a 06 78 69 06 14 92 72 e7 78 45 31 b7 21 56 17 bf 1d 77 40 d6 38 c2 3f 8a 12 31 4a 6e 03 ad 2d"
    " d6 69 a0 41 92 01 40 25 67 46 dd 00 4f 1f fc 6a ce 40 10 57 df 66 fe 62 3e 4b db 41 1f 23 82 35"
    " 9a 07 f6 55 44 06 a7 1c d2 43 16 1b c9 28 72 3f 70 10 14 5f ab 74 14 3e 6e 25 4b 44 d9 50 70 53"
    " 4b 09 42 0f e6 20 d8 2f 5e 2e 8b 77 02 6d 17 71 69 7a ea 7f 28 46 b5 5b 71 6c ba 19 99 3a 76 39"
    " cd 54 8d 17 88 6e 24 01 7e 53 13 33 17 2d 8e 2b be 10 3d 2a 82 05 d1 59 db 63 a1 37 9a 48 d6 30"
    " 46 5c 21 6a 76 7a 1c 0e e7 60 c7 1f 65 0c b8 79 b4 59 f4 27 26 73 9a 79 82 17 ba 50 5c 6d 11 2a"
    " 1b 6e 86 63 3c 0e 92 3f 90 34 02 55 89 60 b5 55 d1 1f 39 2c c2 35 80 2f 7a 2b fd 64 9a 75 e8 4c"
    " f0 04 85 51 a8 01 95 79 ad 2c 5b 3f 60 01 e6 38 d8 41 76 63 42 2a 35 33 19 2c a2 51 51 58 5c 08"
    " ab 17 29 03 c7 0a 77 2b b3 77 ac 30 07 19 ec 2b d0 02 52 03 d3 33 a9 0f f3 5d 25 61 bf 06 ad 22"
    " 71 69 b8 58 e5 0d ca 5f 56 64 0d 70 db 73 a9 56 fd 59 b7 5a e2 0b 0e 33 dd 0d 3c 5b 60 3c 5d 49"
    " a6 59 bd 53 91 6d 5e 4c 8d 31 d9 49 79 50 3d 10 e3 42 ce 61 1d 12 d5 7e ed 60 e1 14 f2 4e 2d 21"
    " f0 33 01 27 96 5a 43 62 8b 5e a7 1f be 2f 09 6f 49 0d 00 4a 70 1c ae 57 77 24 4e 00 72 7e 1e 56"
    " 33 00 8c 46 02 24 cc 5d c6 7a 50 78 c7 24 af 58 34 2d f6 0d 08 47 8a 35 11 1e fb 3c 1c 45 71 2b"
    " 95 52 a7 77 21 07 89 56 f3 75 ef 0f f1 24 0f 12 e7 0a 99 01 52 44 9c 33 8e 5b a1 27 6d 27 a7 0b"
    " 7b 1b dc 60 82 7f 4b 4f 07 70 db 67 d9 57 4a 4f e8 52 12 62 fc 2c 53 20 06 03 39 6a 23 04 80 18"
    " 8a 77 f3 19 f0 16 23 46 37 09 ae 56 5c 67 c2 43 fd 45 ca 65 f2 4f 60 0d cb 22 fd 0b 3b 64 fe 3a"
    " a6 7f f6 3b 79 35 62 44 f8 31 40 18 97 4f 17 32 2a 09 6a 4c 61 02 b5 5f 74 01 65 01 f1 4a 63 33"
    " f4 18 2d 71 69 71 99 6e fe 7a ab 5d e8 2e 2b 7c b4 75 db 6e b6 6f 83 5f d6 6d 2a 3c c2 05 2d 29"
    " db 44 22 05 4f 5f 9a 14 40 65 48 5d ea 15 1d 33 20 69 45 4f 9f 69 3a 48 05 0f 45 3b 6c 7c 20 3b"
    " fe 70 9d 74 f6 61 74 41 f1 31 b0 62 7b 57 50 27 33 15 13 29 08 38 8c 58 56 34 ef 1a ec 00 3c 0f"
    " 42 47 a7 7d 6c 7a 79 4b 87 32 bb 5e b8 58 65 78 f2 4f ed 00 1e 69 69 62 5f 25 a2 24 7e 1f c1 62"
    " cd 7d 8a 2f fe 17 3b 64 b8 18 83 77 fe 60 3b 25 a3 63 bb 34 4f 21 03 5b f4 71 15 5f 9f 6e 31 1a"
    " 04 27 cf 7a 38 68 89 28 77 46 61 18 eb 69 f5 1b c9 5e a8 0b 46 6b ca 6a 2a 42 43 1e 0e 5f 4d 51"
    " 8c 01 3e 41 e9 26 76 30 fa 1d ed 01 5a 6f f4 49 2b 64 1b 46 f2 07 70 7d 57 26 65 13 c5 0b 16 6b"
    " 49 48 e0 65 1c 6e 52 1f b6 51 02 5a 69 3f d7 2b cd 7a bf 2d 80 3e e6 51 0f 67 f2 5c 03 0a cd 21"
    " 61 02 ff 5c 1e 06 ae 33 5f 34 b6 3b 75 4a 81 5d f4 5d 7b 25 5b 2c 5c 0a 27 55 a4 16 45 39 f2 16"
)
TABLE = list(struct.unpack("<256I", bytes.fromhex(_TABLE_RAW.replace(" ", ""))))

TYPE_BYTE = 0x9C
VERSION_ARG = 17

def toupper(b: int) -> int:
    return b - 32 if 0x61 <= b <= 0x7A else b

def checksum(name: str, flag: int, a3: int, a4: int) -> int:
    data = name.encode("utf-8")
    v5 = 0
    v9 = 0
    v10 = (15 * (a4 & 0xFF)) & 0xFF
    v11 = 0
    v12 = (17 * (a3 & 0xFF)) & 0xFF
    for b in data:
        cu = toupper(b)
        idx_a = (cu + (13 if flag else 63)) & 0xFF
        idx_b = (cu + (47 if flag else 23)) & 0xFF
        v17 = (v5 + TABLE[cu]) & 0xFFFFFFFF
        v18 = (TABLE[idx_a] ^ v17) & 0xFFFFFFFF
        v20 = v9 if flag else v11
        v5 = (TABLE[v10] + TABLE[v12] + TABLE[v20] + TABLE[idx_b] * v18) & 0xFFFFFFFF
        v12 = (v12 + 9) & 0xFF
        v10 = (v10 + 13) & 0xFF
        v9 = (v9 + 19) & 0xFF
        v11 = (v11 + 7) & 0xFF
    return v5

def ad76(b: int) -> int:
    return (((b ^ 0x18) + 61) ^ 0xA7) & 0xFF

def c5b(v20: int) -> int:
    v1 = ((((v20 & 0xFFFF) ^ 0x7892) + 19760) & 0xFFFF) ^ 0x3421
    if v1 % 11:
        return 0
    return (v1 // 11) & 0xFFFF

def _best_v20_for_param():
    for v20 in range(0x10000):
        r = c5b(v20)
        if 1 <= r <= 1000:
            return v20, r
    raise RuntimeError("v20 不合法")

def _best_b_for_version():
    best_b, best_n2 = 0, -1
    for b in range(256):
        n2 = ad76(b)
        if n2 > best_n2:
            best_b, best_n2 = b, n2
    if best_n2 < VERSION_ARG:
        raise RuntimeError("不满足版本要求")
    return best_b, best_n2

def keygen(name: str) -> str:
    v20, v21 = _best_v20_for_param()
    b_ver, _n2 = _best_b_for_version()

    chk = checksum(name, flag=1, a3=0, a4=v21 & 0xFF)
    b4 = chk & 0xFF
    b5 = (chk >> 8) & 0xFF
    b6 = (chk >> 16) & 0xFF
    b7 = (chk >> 24) & 0xFF

    b2 = (v20 & 0xFF) ^ b5
    b1 = ((v20 >> 8) & 0xFF) ^ b7
    b0 = b_ver ^ b6

    raw = [b0, b1, b2, TYPE_BYTE, b4, b5, b6, b7]
    hexs = "".join("%02X" % x for x in raw)
    return "-".join(hexs[i:i + 4] for i in range(0, 16, 4))

def _nibble(c: str) -> int:
    o = ord(c)
    if 0x30 <= o <= 0x39:
        return o - 0x30
    if (o - 79) & 0xDF == 0:
        return 0
    if o == 0x6C:
        return 1
    if 0x61 <= o <= 0x7A:
        return (o - 87) & 0xFF
    if 0x41 <= o <= 0x5A:
        return (o - 55) & 0xFF
    return 0

def _decode_license(lic: str):
    s = lic.replace("o", "0").replace("O", "0").replace("l", "1")
    if len(s) != 19 or s[4] != "-" or s[9] != "-" or s[14] != "-":
        return None
    chars = s.replace("-", "")
    if len(chars) != 16:
        return None
    out = []
    for i in range(0, 16, 2):
        hi = _nibble(chars[i])
        lo = _nibble(chars[i + 1])
        out.append(((16 * hi) + lo) & 0xFF)
    out += [0, 0]
    return out

def verify(name: str, lic: str) -> bool:
    """复刻主判定 0x9C 分支,返回 True 表示会得到成功码 45 -> 219。"""
    by = _decode_license(lic)
    if by is None:
        return False
    v39, v40, v41, v42, n5999655_1, v44, v45, v46 = by[:8]
    if v42 != TYPE_BYTE:
        return False

    v20 = ((v44 ^ v41) + ((v46 ^ v40) << 8)) & 0xFFFF
    a1_108 = ad76(v45 ^ v39)
    v21 = c5b(v20)
    n2 = a1_108
    if not (n2 != 0 and (v21 - 1) <= 0x3E7):
        return False
    n255 = n2 if n2 < 2 else 0
    chk = checksum(name, flag=1, a3=n255 & 0xFF, a4=v21 & 0xFF)
    ok = (n5999655_1 == (chk & 0xFF)
          and v44 == ((chk >> 8) & 0xFF)
          and v45 == ((chk >> 16) & 0xFF)
          and v46 == ((chk >> 24) & 0xFF))
    if not ok:
        return False
    # 0x9C: 需要 版本参数 <= 版本上限
    return VERSION_ARG <= a1_108

if __name__ == "__main__":
    name = "Evan"
    lic = keygen(name)
    print("Name    : %s" % name)
    print("License : %s" % lic)
    print("Verify  : %s" % ("PASS" if verify(name, lic) else "FAIL"))

    # Name    : Evan
    # License : 7AE5-159C-9814-796D
    # Verify  : PASS

免费评分

参与人数 13威望 +1 吾爱币 +30 热心值 +12 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
hewok + 1 + 1 谢谢@Thanks!
jixiangyh + 1 + 1 我很赞同!
buluo533 + 1 + 1 用心讨论,共获提升!
GDExecW + 1 我很赞同!
haffman + 1 + 1 我很赞同!
misakibb + 1 + 1 我很赞同!
Issacclark1 + 1 谢谢@Thanks!
孤狼微博 + 1 + 1 CSDN真傻逼
and11 + 1 + 1 我很赞同!
绿雪羚羊 + 1 + 1 就冲那个sb的csdn,必须点个赞!
Songjiujiu + 1 + 1 不明觉厉
Koardor + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

inphie 发表于 2026-6-17 15:48
哈哈只要在骂csdn,我们就是朋友,支持
windy3000 发表于 2026-6-17 15:40
atguudp 发表于 2026-6-17 16:09
laoser 发表于 2026-6-17 22:54
CSDN已经很多年没看过了,都是掘金
sdieedu 发表于 2026-6-17 17:13
csdn 啥玩意啊, 动不动vip,问题是我的文章咋只能vip看? 本来免费分享的
skx258456 发表于 2026-6-17 18:30
谁能告诉我干嘛用的怎么用的呜呜呜
52soft 发表于 2026-6-17 18:40
值得学习
sangern 发表于 2026-6-17 19:50

CSDN什么文章都要收费。向百度看齐了
QiaoSatoshiMoto 发表于 2026-6-17 19:56
学到了,而且CSDN确实恶心
孤狼微博 发表于 2026-6-17 22:02
我本地注册失败,是不是我之前打过补丁的原因呢,别人是注册成功的,我卸载了之后没重启电脑
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-7-10 18:35

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表