首页 > 其他分享 >sublime_text_build_4169 分析

sublime_text_build_4169 分析

时间:2024-07-28 17:07:53浏览次数:6  
标签:__ sub text QWORD int64 build str data sublime

sublime_text 记录

目录

sublime_text 4169 版本4.1.6.9

1、定位注册对话框

搜索"Enter License",

image-20240728150521384

函数交叉引用,定位到license_window

license_window_1400A25D2

_QWORD *__fastcall license_window_1400A25D2(_QWORD *a1, __int64 a2, int a3, __int64 a4)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v42 = 0xFFFFFFFFFFFFFFFEui64;
  sub_140005412();
  *a1 = &license_window::`vftable';
  a1[1] = &license_window::`vftable';
  a1[0x4D] = a4;
  v40 = a1;
  v35 = a1 + 0x52;
  sub_140032268(a1 + 0x52, a2);
  sub_1401642B0(v40, "dialog window");
  v8 = operator new(0x220ui64);
  v34 = 0i64;
  button_control = v8;
  sub_1401861A0(v8, &v34);
  v9 = button_control;
  v40[0x4E] = button_control;
  v29 = &unk_14075F4E1;
  v30 = "";
  (*(void (__fastcall **)(void *))(*(_QWORD *)v9 + 0x1E8i64))(v9);
  button_control = operator new(0x260ui64);
  v10 = &v25;
  string_140001FD0(&v25, "https://www.sublimehq.com/store/text");
  if ( v27 >= 0x10 )
    v10 = (__int128 *)v25;
  v36[0] = (__int64)v10;
  v36[1] = (__int64)v10 + (_QWORD)v26;
  v11 = button_control;
  sub_1401861A0(button_control, v36);
  *v11 = &link_label_control::`vftable';
  v11[1] = &link_label_control::`vftable';
  v11[0x4B] = 0i64;
  str_clear_140004410(&v25);
  *(_QWORD *)&v25 = ___7___Func_impl_no_alloc_V_lambda_2___0___0license_window__QEAA_AEBV__function___A6AXXZ_std__PEAVtext_control_environment__PEAUlicense_info___Z_X__V_std__6B_;
  *((_QWORD *)&v25 + 1) = v11;
  v28 = &v25;
  sub_1400328D4(&v25, v11 + 0x44);
  sub_140005A2A((__int64)&v25, v12);
  sub_1401642B0(v11, "label_control link_label");
  v38 = operator new(0x2B8ui64);
  sub_1400A2D10(v38, 1i64);
  v13 = v38;
  sub_14018881A(v38, v40[0x4E], 0i64);
  sub_14018881A(v13, v11, 1i64);
  button_control = operator new(0x368ui64);
  button_control_14015314C((__int64)button_control);
  v14 = button_control;
  v40[0x51] = button_control;
  *(_QWORD *)v31.u._Buf = "Use License";
  *(_QWORD *)&v31.u._Buf[8] = "";
  sub_140153C02((__int64)v14, (__int128 *)v31.u._Buf);
  v15 = v40[0x51];
  *(_QWORD *)&v25 = ___7___Func_impl_no_alloc_V_lambda_3___0___0license_window__QEAA_AEBV__function___A6AXXZ_std__PEAVtext_control_environment__PEAUlicense_info___Z_X__V_std__6B_;
  *((_QWORD *)&v25 + 1) = v40;
  v28 = &v25;
  sub_140153214(v15, &v25);
  sub_140005A2A((__int64)&v25, v16);
  button_control = operator new(0x3B8ui64);
  LOBYTE(v17) = 1;
  sub_14047E4F4((_DWORD)button_control, a3, v17, 0, 1);
  v18 = button_control;
  v40[0x4F] = button_control;
  v18[0x71] = "license:input";
  v39 = operator new(0x318ui64);
  sub_1400FDEDA(v39, v18, v18 + 0x22);
  v40[0x50] = v39;
  button_control = operator new(0x1B0ui64);
  sub_14017BDF0(button_control, 3i64, 1i64);
  v19 = button_control;
  (*(void (__fastcall **)(void *))(*(_QWORD *)button_control + 0x1F0i64))(button_control);
  (*(void (__fastcall **)(_QWORD *))(*v19 + 0x1E8i64))(v19);
  *(_DWORD *)(v19[0x26] + 4i64) = 0x3F800000;
  *(_DWORD *)v19[0x29] = 0x3F800000;
  sub_14017BF3E((_DWORD)v19, (_DWORD)v13, 0, 0, 0);
  sub_14017BF3E((_DWORD)v19, v40[0x50], 1, 0, 0);
  sub_14017BF3E((_DWORD)v19, v40[0x51], 2, 0, 0);
  sub_140162720(v40, v19);
  *(_QWORD *)&v25 = 0i64;
  *((_QWORD *)&v25 + 1) = 0x200i64;
  v26 = &v27;
  v20 = v36;
  sub_1400A134D(v36);
  if ( v37 >= 0x10 )
    v20 = (__int64 *)v36[0];
  v21 = sub_140122FEA(v20, &v25, 0x40000000i64);
  str_clear_140004410(v36);
  if ( v21 )
  {
    v22 = *(_QWORD *)(*(_QWORD *)(v40[0x4F] + 0x128i64) + 0x848i64);
    v32 = v26;
    v33 = (__int64)v26 + v25;
    v23 = v36;
    sub_140385275(v36);
    if ( v37 >= 4 )
      v23 = (__int64 *)v36[0];
    v31._Mysize = (size_t)v23;
    v31._Myres = (size_t)v23 + 4 * v36[2];
    sub_1403F3CEE(v22, 0, (unsigned int)&v31._Mysize, 0, 1);
    sub_140019D58(v36);
  }
  sub_1401309D8(&v25);
  return v40;
}

定位按钮事件lambda

image-20240728151319595

2、注册函数on_ok_clicked_license_window_1400A3F60

void __fastcall on_ok_clicked_license_window_1400A3F60(__int64 a1)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v23 = 0xFFFFFFFFFFFFFFFEui64;
  v1 = *(_QWORD *)(a1 + 8);
  gettext_14047A122(*(_QWORD *)(v1 + 0x278), (__int64)&v13[56]);
  memset(xor_str, 0, sizeof(xor_str));
  v18 = 0xFi64;
  v20 = 0i64;
  v19 = 0i64;
  v21 = 0xFi64;
  sub_1400A154A(*(_OWORD **)(v1 + 0x268), xor_str);
  sub_1400A0FC0(xor_str);
  if ( *(_QWORD *)&v13[72] )
  {
    // need ret 0
    v2 = check_lic_1400A19BC(
           &v14,
           (_QWORD *)(*(_QWORD *)(v1 + 0x268) + 0x10i64),
           *(_DWORD **)(v1 + 0x268),
           (unsigned int *)&v22,
           (int *)(*(_QWORD *)(v1 + 0x268) + 0xCi64),
           (_BYTE *)(*(_QWORD *)(v1 + 0x268) + 4i64));
    v3 = *(_QWORD *)(v1 + 0x268);
    *(_BYTE *)(v3 + 5) = v2 == 0;
    if ( v2 )
    {
      switch ( v2 )
      {
        case 1:
          // 这似乎是 Sublime Merge 许可证密钥,而不是 Sublime Text 密钥
          callback_work_14013685C((__int64)&unk_1408E8998, (__int64)sub_1400A2EAF, 0i64);
          break;
        case 2:
          // 该许可证密钥似乎无效。
          callback_work_14013685C((__int64)&unk_1408E8998, (__int64)sub_1400A2EBD, 0i64);
          break;
        case 3:
          // 许可证密钥已失效
          callback_work_14013685C((__int64)&unk_1408E8998, (__int64)sub_1400A2ECB, 0i64);
          break;
        case 4:
          // 该许可证密钥因被共享而失效
          callback_work_14013685C((__int64)&unk_1408E8998, (__int64)sub_1400A2ED9, 0i64);
          break;
        case 5:
          // 由于您的订阅已结束或已取消,许可证密钥已失效。
          callback_work_14013685C((__int64)&unk_1408E8998, (__int64)sub_1400A2EE7, 0i64);
          break;
        default:
          break;
      }
    }
    else
    {
      vec_pop_14000233C((_QWORD *)(v3 + 0x30), &v14);
      string_140003006(&v15, &v14);
      v16 = v22;
      *(_QWORD *)xor_str = ___7___Func_impl_no_alloc_V_lambda_4___0__on_ok_clicked_license_window__QEAAXXZ_X__V_std__6B_;
      *(std_string *)&xor_str[8] = v15;
      v15._Mysize = 0i64;
      v15._Myres = 0xFi64;
      v15.u._Buf[0] = 0;
      LODWORD(v18) = v22;
      *((_QWORD *)&v19 + 1) = xor_str;
      sub_14020C932(xor_str, 0x1D4C0i64);
      sub_140005A2A((__int64)xor_str, v5);
      str_clear_140004410(&v15);
      // MachineGuid md5
      gen_lic_xor_data_1400A0FEE((__int64)xor_str);
      lic_data = &v14;
      // xor lic
      license_file_xor_1400A1307(*(std_string **)xor_str, &v14);
      sub_14000439A((std_vector_str *)xor_str);
      Ptr = v14.u._Ptr;
      lic_data_sz = v14._Mysize;
      Myres = v14._Myres;
      v10 = xor_str;
      save_lic_1400A134D((__int64)xor_str);
      if ( Myres >= 0x10 )
        lic_data = (std_string *)Ptr;
      if ( *(_QWORD *)&xor_str[0x18] >= 0x10ui64 )
        v10 = *(char **)xor_str;
      // 保存lic文件到
      // C:\Users\xxx\AppData\Roaming\Sublime Text\Local\License.sublime_license
      v11 = write_lic_1401230FC(v10, lic_data, lic_data_sz, 1);
      str_clear_140004410((std_string *)xor_str);
      if ( !v11 )
        callback_work_14013685C((__int64)&unk_1408E8998, (__int64)sub_1400A2D84, 0i64);
      v12 = thread_1401329DC(net_license_notification_1400A1583, (LPVOID)v22);
      CloseHandle(v12);
      if ( *(_BYTE *)(*(_QWORD *)(v1 + 0x268) + 4i64) )
        callback_work_14013685C((__int64)&unk_1408E8998, (__int64)purchasing_cb_1400A2E2E, 0i64);
      else
        callback_work_14013685C((__int64)&unk_1408E8998, (__int64)purchasing_cb_1400A2EA1, 0i64);
    }
  }
  else
  {
    v4 = xor_str;
    save_lic_1400A134D((__int64)xor_str);
    if ( *(_QWORD *)&xor_str[0x18] >= 0x10ui64 )
      v4 = *(_BYTE **)xor_str;
    sub_140123489(v4);
    str_clear_140004410((std_string *)xor_str);
  }
  if ( *(_QWORD *)(v1 + 0x2C8) )
    sub_140005A7E(v1 + 0x290);
  (*(void (__fastcall **)(_QWORD))(**(_QWORD **)(v1 + 0x28) + 0x18i64))(*(_QWORD *)(v1 + 0x28));
  str_clear_140004410(&v14);
}

check_lic_1400A19BC(to patch)

patch点 修改此函数返回0

该函数需返回0

image-20240728152916158

parse_lic_1405B0E48

解析lic格式,并进行签名校验

// 需返回1
__int64 __fastcall parse_lic_1405B0E48(
        std_string *input_lic,
        std_string *emb,
        std_string *out_username,
        int *lic_type,
        std_string *prefix,
        std_string *random,
        std_string *unknow)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v16 = -2ui64;
  *(_OWORD *)&lic_verify_data[96] = 0i64;
  *(_QWORD *)&lic_verify_data[112] = 0i64;
  *(_QWORD *)&lic_verify_data[120] = 0xFi64;
  if ( (unsigned __int8)split_1405B0F77(
                          input_lic,
                          out_username,
                          lic_type,
                          prefix,
                          random,
                          unknow,
                          (std_string *)&lic_verify_data[96]) )
  {
    // ret==>
    // Mifeng User
    // Single User License
    // EA7E-1184812
    User_License_1405B13B8(&v14, out_username, *lic_type, prefix, random, unknow);
    // ibtomcrypt中rsa_verify_hash
    // pkcs1_15 签名验证,sha1
    LOBYTE(v10) = verify_rsa_signature_1405B1B69(&v14, &data, emb);
    v11 = v10;
    str_clear_140004410(&v14);
  }
  else
  {
    v11 = 0;
  }
  str_clear_140004410(&data);
  return v11;
}

verify_rsa_signature_1405B1B69

bool __fastcall verify_rsa_signature_1405B1B69(std_string *userinfo, std_string *data, std_string *embed)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  // LibTomMath
  memmove(&qword_1408F3A20, &off_1406DE250, 0x1A0ui64);
  sub_1404E87B8(&off_1406DE0A0);
  stat = sub_1404E8754("sha1");
  sha1hash_sz = 0x80;
  Mysize = userinfo->_Mysize;
  if ( userinfo->_Myres >= 0x10 )
    userinfo = (std_string *)userinfo->u._Ptr;
  if ( (unsigned int)calc_sha1_1404E504C(stat, (__int64)userinfo, Mysize, (__int64)sha1hash, &sha1hash_sz) )
    return 0;
  v8 = SLODWORD(embed->_Mysize) / 2;
  if ( embed->_Myres >= 0x10 )
    embed = (std_string *)embed->u._Ptr;
  hexstr2bytes_1405B1B24((__int64)embed, (__int64)v16, v8);// hexstr??to bytes
  if ( (unsigned int)rsa_import_1404ED7E8((__int64)v16, v8, v13) )
    return 0;
  sigdata_sz = LODWORD(data->_Mysize) >> 1;
  if ( data->_Myres >= 0x10 )
    data = (std_string *)data->u._Ptr;
  hexstr2bytes_1405B1B24((__int64)data, (__int64)sigdata, sigdata_sz);
  pub_key_ = 0;
  // sig: 签名的二进制数据。
  // siglen: 签名的长度。
  // hash: 要验证的哈希值。
  // hashlen: 哈希值的长度。
  // padding: 填充方案(如LTC_PKCS_1_V1_5)。
  // hash_idx: 哈希算法的索引(如find_hash("sha256"))。
  // stat: 返回的验证状态(0表示验证失败,1表示验证成功)。
  // key: 公钥结构体。
  if ( (unsigned int)rsa_verify_hash_1404EE0D8(
                       (__int64)sigdata,
                       sigdata_sz,
                       (__int64)sha1hash,
                       sha1hash_sz,
                       1,
                       stat,
                       0,
                       &pub_key_,
                       (__int64)v13) )
    return 0;
  sub_1404ED778(v13);
  return pub_key_ == 1;
}

3、网络校验

patch 线程函数直接ret

1、net_check_license_1400A30E3

2、net_license_notification_1400A1583(可选,在check_lic_1400A19BC patch后可以忽略)

image-20240728160159474

net_check_license_1400A30E3(to patch)

image-20240728160244863

BOOL __fastcall clicked_license_net_check_1400A3752(_QWORD *a1, int a2)
{
  void *v4; // rax
  _DWORD *Block; // [rsp+20h] [rbp-10h]

  Block = operator new(0x28ui64);
  string_140003006(Block, a1);
  Block[8] = a2;
  v4 = (void *)thread_1401329DC(net_check_license_1400A30E3, Block);
  return CloseHandle(v4);
}

net_check_license_1400A30E3

image-20240728160359922

4、other

由于该n 未被分解factordb.com

因此需进行patch

image-20240728161227248

image-20240728161248297

License.sublime_license解析&签名验证脚本


import binascii
import hashlib
from Crypto.PublicKey import RSA
from Crypto.Util.number import long_to_bytes, bytes_to_long
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA1


import winreg

EMBEDDED_XOR_DATA = bytes([0x87, 0x36, 0x2A, 0x87, 0xBA, 0xB1, 0xBE, 0x9D, 0x31, 0xFF,
                           0x31, 0x40, 0xBA, 0xB6, 0xB6, 0xB6, 0xB2, 0xB7, 0xB4, 0x36,
                           0x3C, 0xB7, 0x87, 0x36, 0x30, 0xB5, 0x36, 0x36, 0xB7, 0x6F,
                           0xCC, 0x15, 0xF2, 0xD5, 0x40, 0x72, 0x66, 0xFD, 0xBB, 0x4C,
                           0xA5, 0x0E, 0xC3, 0xBB, 0xAE, 0xEB, 0xDC, 0x6B, 0xC9, 0xDA,
                           0xD9, 0x7E, 0x9C, 0x1B, 0xB9, 0x05, 0x2A, 0xEE, 0x56, 0x6E,
                           0x19, 0xD0, 0x3E, 0xBB, 0x9C, 0x3F, 0x74, 0x1C, 0x6B, 0x18,
                           0x49, 0xCA, 0xFD, 0x84, 0x6B, 0x76, 0x08, 0x09, 0xE4, 0xAD,
                           0x92, 0xAB, 0x58, 0xBB, 0x25, 0x88, 0xB1, 0x09, 0xCE, 0x05,
                           0x85, 0x32, 0xEE, 0x1B, 0x49, 0x5E, 0x31, 0x62, 0x56, 0xE9,
                           0xFA, 0xA0, 0xD1, 0x5D, 0xE1, 0x73, 0x56, 0xB1, 0xE0, 0x4D,
                           0xC3, 0x6C, 0xBE, 0xC0, 0x74, 0x4C, 0xC2, 0x35, 0x00, 0x3B,
                           0x63, 0xCC, 0x05, 0x70, 0x4E, 0x05, 0xE5, 0x03, 0x1E, 0xF1,
                           0x8A, 0xA2, 0x41, 0x19, 0xD9, 0x5E, 0x94, 0xCA, 0xE3, 0x72,
                           0xFF, 0xAC, 0x44, 0x57, 0x07, 0x2E, 0x97, 0xAE, 0xBC, 0x78,
                           0x04, 0xA9, 0xEC, 0x52, 0xBE, 0x74, 0x8C, 0xB5, 0xB6, 0xA6])


def get_machine_guid():
    try:
        registry_key = winreg.OpenKey(
            winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Cryptography", 0, winreg.KEY_READ)
        value, regtype = winreg.QueryValueEx(registry_key, "MachineGuid")
        winreg.CloseKey(registry_key)
        return value
    except FileNotFoundError:
        return None


def int_to_bytes(n: int, order='little') -> bytes:
    # 获取整数的位长度
    bit_length = n.bit_length()
    # 计算所需的最小字节数
    byte_length = (bit_length + 7) // 8
    # 转换为字节序列,使用大端字节序
    byte_array = n.to_bytes(byte_length, byteorder=order)
    return byte_array


def import_rsa_der_pubkey(binary_data):
    try:
        # 从二进制数据中导入RSA密钥
        rsa_key = RSA.import_key(binary_data)
        print("RSA密钥导入成功!")
        print('e:', rsa_key.e)
        print('n:', rsa_key.n)
        return rsa_key
    except ValueError as e:
        print(f"导入RSA密钥失败: {e}")


def verify_rsa_signature(public_key, signature, message):
    try:
        # 导入公钥
        # public_key = RSA.import_key(public_key_pem)

        # 计算消息的哈希值(使用SHA-1)
        h = SHA1.new(message)

        # 验证签名
        pkcs1_15.new(public_key).verify(h, signature)
        print("签名验证成功!")
        return True
    except (ValueError, TypeError) as e:
        print(e)
        print("签名验证失败!")
        return False


def get_embedded_pubkey() -> str:
    ret = b''
    for i in range(0xa0):
        x = (EMBEDDED_XOR_DATA[i] ^ 0xb7) & 0xff
        ret += x.to_bytes(1, 'little')
    ret = ret.hex().upper()
    return ret


EMBEDDED_PUBKEY_STR = get_embedded_pubkey()


'''
#失效的lic,只为检查签名验证
—– BEGIN LICENSE —–
Mifeng User
Single User License
EA7E-1184812
C0DAA9CD 6BE825B5 FF935692 1750523A
EDF59D3F A3BD6C96 F8D33866 3F1CCCEA
1C25BE4D 25B1C4CC 5110C20E 5246CC42
D232C83B C99CCC42 0E32890C B6CBF018
B1D4C178 2F9DDB16 ABAA74E5 95304BEF
9D0CCFA9 8AF8F8E2 1E0A955E 4771A576
50737C65 325B6C32 817DCB83 A7394DFA
27B7E747 736A1198 B3865734 0B434AA5
—— END LICENSE ——

'''


def test():

    print('embedded_pubkey:', EMBEDDED_PUBKEY_STR)
    x = hashlib.sha256(EMBEDDED_PUBKEY_STR.encode()).digest()
    print('sha256 embedded key:', x.hex())
    '''
    sha256[1] ^ 0x34 | sha256[0xD] ^ 0xD7 | sha256[0x1E] ^ 0x56
    '''
    if (x[1] ^ 0x34 | x[0xD] ^ 0xD7 | x[0x1E] ^ 0x56) != 0:
        print('embedded_pubkey check sha256 error!')
    else:
        print('check embedded_pubkey sha256 success!')
    '''
Mifeng User
Single User License
EA7E-1184812
    '''
    userinfo = binascii.a2b_hex(
        '4D6966656E6720557365720A53696E676C652055736572204C6963656E73650A454137452D31313834383132')
    msg_sha1 = hashlib.sha1(userinfo).digest()
    print('[#]msg_sha1:', msg_sha1.hex())

    rsa_key = import_rsa_der_pubkey(binascii.a2b_hex(EMBEDDED_PUBKEY_STR))
    user_data = binascii.a2b_hex(
        'C0DAA9CD6BE825B5FF9356921750523AEDF59D3FA3BD6C96F8D338663F1CCCEA1C25BE4D25B1C4CC5110C20E5246CC42D232C83BC99CCC420E32890CB6CBF018B1D4C1782F9DDB16ABAA74E595304BEF9D0CCFA98AF8F8E21E0A955E4771A57650737C65325B6C32817DCB83A7394DFA27B7E747736A1198B38657340B434AA5')

    print(
        '\n###############################[manual verify]###############################')
    i_data = bytes_to_long(user_data)
    data = pow(i_data, rsa_key.e, rsa_key.n)
    # print('rsa dec:',int_to_bytes(data).hex())

    # 解析解密后的数据
    # 对于PKCS#1 v1.5 签名,结构是:
    # 00 01 ff ... ff 00 [ASN.1编码的哈希算法ID和哈希值]
    # 查找ASN.1编码的起始位置(0x00之后)
    data = long_to_bytes(data)
    start_idx = data.index(b'\x00', 2) + 1
    asn1_encoded = data[start_idx:]

    dec_msg = asn1_encoded[-20:]
    print('[#]dec_msg:', dec_msg.hex())
    print('msg_sha1==dec_msg', msg_sha1 == dec_msg)
    print(
        '###############################[manual verify end]###############################\n\n')

    print('pkcs1_15 verify:')
    verify_rsa_signature(rsa_key, user_data, userinfo)


def calc_lic_xor_table() -> bytes:
    # MachineGuid=b'692a3bbc-1b8b-44c2-b95f-8a18dc8b5664'
    MachineGuid = get_machine_guid().encode()
    hs = hashlib.md5(MachineGuid).digest()
    return hs


XOR_TABLE = calc_lic_xor_table()


def lic_file_parse(path: str):
    with open(path, 'rb') as f:
        data = bytearray(f.read())
    for i in range(len(data)):
        data[i] ^= XOR_TABLE[i & 0xf]
    print("License.sublime_license dec:")
    print(data.decode(encoding='utf-8'))


if __name__ == "__main__":
    # path=r'C:\Users\xxxx\AppData\Roaming\Sublime Text\Local\License.sublime_license'
    # lic_file_parse(path)
    test()
    pass

标签:__,sub,text,QWORD,int64,build,str,data,sublime
From: https://www.cnblogs.com/DirWang/p/18328449

相关文章

  • text2sql-workshop
    text2sql-workshophttps://github.com/fanqingsong/text2sql-workshopText2SQLWorkshopUsingOpenAI,LangchainandPostgresqltoTalktoYourDataOverviewThisrepodemonstratesthepowerofLargeLanguageModelsandGenerativeAIforsimplifyi......
  • Sublime Text提取正则表达式匹配的文本
    最近在使用爬虫分析一些网站的返回数据json的时候,想要批量提取里面的一些网址,写代码当然可以完成。如果对于没有代码基础的人来说,也可以使用SUblime来实现。比如我想提取以http://开头的,以.webp为结束的网址可以这样写操作。Ctrl+F,打开查找,开启第一个正则表达式,里面这样填写......
  • Building a Car Rental Website
    WebApplicationDevelopment:BuildingaCarRentalWebsiteSummer2024AllocationThiscourseworkisworth100%ofthemarksformoduleYouwillalsoneedskillsfromthefollowingmodules:(PythonProgramming)(Designreporting)(Databasedesign)(Secu......
  • marktext入门
    快捷键marktext/docs/KEYBINDINGS_WINDOWS.mdatmaster·marktext/marktext·GitHubFilemenuIdDefaultDescriptionfile.new-fileCtrl+NNewfilefile.new-tabCtrl+TNewtabfile.open-fileCtrl+OOpenmarkdownfilefile.open-folderCtrl+Shift+O......
  • MySQL索引详解full-text,b-tree,hash,r-tree
    一、MySQL索引类型mysql里目前只支持4种索引分别是:full-text,b-tree,hash,r-treeb-tree索引应该是mysql里最广泛的索引的了,除了archive基本所有的存储引擎都支持它.1.full-text索引full-text在mysql里仅有myisam支持它,而且支持full-text的字段只有char、varchar、text数据类型......
  • Hbuilder发布app应用流程
    使用HBuilder发布App应用的流程可以分为以下几个步骤。HBuilder是一款高效的前端开发工具,特别适合移动端应用的开发。以下是详细的步骤:1.开发准备安装HBuilder:从DCloud官方网站下载并安装HBuilder。创建项目:打开HBuilder,新建一个移动App项目,选择合适的模板进行开......
  • 索引结构—B+Tree索引、Hash索引、Full-Text(全文)索引、R-Tree(空间)索引
    一、概述在数据库系统中,索引是一种用于加快数据检索的数据结构。不同的索引结构适用于不同的查询场景和数据特性。索引按照不同角度可以划分不同类型的索引。按照数据结构可以划分B+Tree索引、Hash索引、FULLTEXT(全文)索引、R-Tree(空间)索引二、索引结构mysql的索引是作用于......
  • 常用System.Text.Json的JsonSerializerOptions配置
    newJsonSerializerOptions{PropertyNamingPolicy=JsonNamingPolicy.CamelCase,//驼峰命名规则Encoder=JavaScriptEncoder.Create(UnicodeRanges.BasicLatin,//基础拉丁文字母UnicodeRanges.CjkUnifiedIdeographs,//中日韩统一的表意文字......
  • 【YOLOv8改进 - 注意力机制】ContextAggregation : 上下文聚合模块,捕捉局部和全局上下
    YOLOv8目标检测创新改进与实战案例专栏专栏目录:YOLOv8有效改进系列及项目实战目录包含卷积,主干注意力,检测头等创新机制以及各种目标检测分割项目实战案例专栏链接:YOLOv8基础解析+创新改进+实战案例介绍摘要卷积神经网络(CNNs)在计算机视觉中无处不在,具有众多高效......
  • 【YOLOv8改进- 多模块融合改进】GhostConv + ContextAggregation 幽灵卷积与上下文聚
    YOLOv8目标检测创新改进与实战案例专栏专栏目录:YOLOv8有效改进系列及项目实战目录包含卷积,主干注意力,检测头等创新机制以及各种目标检测分割项目实战案例专栏链接:YOLOv8基础解析+创新改进+实战案例ContextAggregation介绍摘要卷积神经网络(CNNs)在计算机视觉中无......