ctf-re:z3 + rc4 + windws hook + XTEA -- GHCTF FishingKit

发布于:2025-04-02 ⋅ 阅读:(22) ⋅ 点赞:(0)

分析主函数

int __fastcall main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rdx
  __int64 v4; // r8
  __int64 v5; // rdx
  __int64 v6; // r8
  __int64 v7; // rdx
  __int64 v8; // r8
  __int64 v10; // rdx
  __int64 v11; // r8
  char v13[24]; // [rsp+20h] [rbp-98h] BYREF
  char v14[56]; // [rsp+38h] [rbp-80h] BYREF
  char Str1[56]; // [rsp+70h] [rbp-48h] BYREF

  memset(v13, 0, 0x14uLL);
  memset(v14, 0, 0x32uLL);
  memset(Str1, 0, 0x32uLL);
  sub_140002FD0("Give me the bait:", argv, envp);
  sub_140003050("%s", v13);
  if ( check1((unsigned __int8 *)v13) )
  {
    sub_140002FD0("Yes!This bait is a good one.\n\n", v3, v4);
    sub_140002FD0("Give me the second thing:", v5, v6);
    sub_140003050("%s", v14);
    sub_140002FD0("\nFishing...\n\n", v7, v8);
    Sleep(0x3E8u);
    check2(v14, (__int64)Str1, (__int64)v13);
    if ( strcmp(Str1, &Str2) )
      sub_140002FD0("Didn't the fish take the bait?\n", v10, v11);
    else
      sub_140002FD0("Did the fish take the bait?\n", v10, v11);
  }
  else
  {
    sub_140002FD0("Oops...This bait is terrible.\n", v3, v4);
  }
  system("pause");
  return 0;
}

第一层check

bool __fastcall check1(unsigned __int8 *a1)
{
  return 202 * a1[8] + 216 * a1[5] - 4 * a1[4] - 330 * a1[9] - 13 * a1[4] - 268 * a1[6] == -14982
      && 325 * a1[8] + 195 * *a1 + 229 * a1[1] - 121 * a1[6] - 409 * a1[6] - (a1[1] << 7) == 22606
      && 489 * a1[1] + 480 * a1[6] + 105 * a1[2] + 367 * a1[3] - 135 * a1[4] - 482 * a1[9] == 63236
      && 493 * a1[1] - 80 * a1[4] - 253 * a1[8] - 121 * a1[2] - 177 * *a1 - 243 * a1[9] == -39664
      && 275 * a1[4] + 271 * a1[6] + 473 * a1[7] - 72 * a1[5] - 260 * a1[4] - 367 * a1[4] == 14255
      && 286 * *a1 + 196 * a1[7] + 483 * a1[2] + 442 * a1[1] - 495 * a1[8] - 351 * a1[4] == 41171
      && 212 * a1[2] + 283 * a1[7] - 329 * a1[8] - 429 * a1[9] - 362 * a1[2] - 261 * a1[6] == -90284
      && 456 * a1[5] + 244 * a1[7] + 92 * a1[4] + 348 * a1[7] - 225 * a1[1] - 31 * a1[2] == 88447
      && 238 * a1[9] + 278 * a1[7] + 216 * a1[6] + 237 * *a1 + 8 * a1[2] - 17 * a1[9] == 83838
      && 323 * a1[9] + 121 * a1[1] + 370 * a1[7] - (a1[4] << 6) - 196 * a1[9] - 422 * *a1 == 26467
      && 166 * a1[9] + 90 * a1[1] + 499 * a1[2] + 301 * a1[8] - 31 * a1[2] - 206 * a1[2] == 88247
      && 355 * *a1 + 282 * a1[4] + 44 * a1[9] + 359 * a1[8] - 167 * a1[5] - 62 * a1[3] == 76658
      && 488 * a1[6] + 379 * a1[9] + 318 * a1[2] - 85 * a1[1] - 357 * a1[2] - 277 * a1[5] == 35398
      && 40 * *a1 + 281 * a1[4] + 217 * a1[5] - 241 * a1[1] - 407 * a1[7] - 309 * a1[7] == -35436
      && 429 * a1[3] + 441 * a1[3] + 115 * a1[1] + 96 * a1[8] + 464 * a1[1] - 133 * a1[7] == 157448;
}

化简a[1] << 7 为 a[1] * 2**7 a1[4] << 6 为 a1[4] * 2**6 *a1 是 a1[0]

用z3求解

from z3 import *  
  
# 创建求解器  
s = Solver()  
  
# 声明变量 a1[0] 到 a1[9]a1 = [Int('a1_%d' % i) for i in range(10)]  
  
# 添加变量范围约束:0 <= a1[i] <= 255  
for i in range(10):  
    s.add(a1[i] >= 0, a1[i] <= 255)  
  
# 添加方程  
s.add(202*a1[8] + 216*a1[5] - 17*a1[4] - 330*a1[9] - 268*a1[6] == -14982)  
s.add(325 * a1[8] + 195 * a1[0] + 229 * a1[1] - 121 * a1[6] - 409 * a1[6] - (a1[1] * (2**7)) == 22606)  
s.add(489*a1[1] + 480*a1[6] + 105*a1[2] + 367*a1[3] - 135*a1[4] - 482*a1[9] == 63236)  
s.add(493*a1[1] - 80*a1[4] - 253*a1[8] - 121*a1[2] - 177*a1[0] - 243*a1[9] == -39664)  
s.add(-352*a1[4] + 271*a1[6] + 473*a1[7] - 72*a1[5] == 14255)  
s.add(286*a1[0] + 196*a1[7] + 483*a1[2] + 442*a1[1] - 495*a1[8] - 351*a1[4] == 41171)  
s.add(-150*a1[2] + 283*a1[7] - 329*a1[8] - 429*a1[9] - 261*a1[6] == -90284)  
s.add(456*a1[5] + 592*a1[7] + 92*a1[4] - 225*a1[1] - 31*a1[2] == 88447)  
s.add(221*a1[9] + 278*a1[7] + 216*a1[6] + 237*a1[0] + 8*a1[2] == 83838)  
s.add(323 * a1[9] + 121 * a1[1] + 370 * a1[7] - (a1[4] * (2**6)) - 196 * a1[9] - 422 * a1[0] == 26467)  
s.add(166*a1[9] + 90*a1[1] + 262*a1[2] + 301*a1[8] == 88247)  
s.add(355*a1[0] + 282*a1[4] + 44*a1[9] + 359*a1[8] - 167*a1[5] - 62*a1[3] == 76658)  
s.add(488*a1[6] + 379*a1[9] - 39*a1[2] - 85*a1[1] - 277*a1[5] == 35398)  
s.add(40*a1[0] + 281*a1[4] + 217*a1[5] - 241*a1[1] - 716*a1[7] == -35436)  
s.add(870*a1[3] + 579*a1[1] + 96*a1[8] - 133*a1[7] == 157448)  
  
# 检查是否有解  
if s.check() == sat:  
    m = s.model()  
    for i in range(10):  
        print(f'a1[{i}] = {chr(m[a1[i]].as_long())}')  
else:  
    print("没有可行解")

得到

a1[0] = D
a1[1] = e
a1[2] = l
a1[3] = u
a1[4] = x
a1[5] = e
a1[6] = B
a1[7] = a
a1[8] = i
a1[9] = t

DeluxeBait

分析check2发现为rc4变种

__int64 __fastcall sub_140002460(const char *a1, __int64 a2, __int64 a3)
{
  __int64 result; // rax
  unsigned __int8 v4; // [rsp+20h] [rbp-18h]
  unsigned __int8 v5; // [rsp+21h] [rbp-17h]
  unsigned int i; // [rsp+24h] [rbp-14h]
  unsigned int v7; // [rsp+28h] [rbp-10h]

  v4 = 0;
  v5 = 0;
  sub_1400028B0(a3);
  v7 = strlen(a1);
  for ( i = 0; i < v7; ++i )
  {
    v5 += byte_1400060C0[++v4];
    std::swap<char,0>(&byte_1400060C0[v4], &byte_1400060C0[v5]);
    *(_BYTE *)(a2 + i) = byte_1400060C0[(unsigned __int8)(byte_1400060C0[v5] + byte_1400060C0[v4])] ^ a1[i];
    *(_BYTE *)(a2 + i) ^= 0x14u;
  }
  result = v7;
  *(_BYTE *)(a2 + v7) = 0;
  return result;
}
#include <stdio.h>  
#include <stdint.h>  
#include <string.h>  
  
#define SWAP(a, b) { uint8_t temp = a; a = b; b = temp; }  
  
void rc4_init(uint8_t *key, uint8_t *S, int keylen) {  
    int i, j;  
    for (i = 0; i < 256; i++) {  
        S[i] = i;  
    }  
    for (i = 0, j = 0; i < 256; i++) {  
        j = (j + S[i] + key[i % keylen]) % 256;  
        SWAP(S[i], S[j]);  
    }  
}  
  
void rc4_crypt(uint8_t *S, uint8_t *data, int datalen) {  
    int i = 0, j = 0, k;  
    for (k = 0; k < datalen; k++) {  
        i = (i + 1) % 256;  
        j = (j + S[i]) % 256;  
        SWAP(S[i], S[j]);  
        data[k] ^= S[(S[i] + S[j]) % 256];  
        data[k] ^= 0x14;  
    }  
}

 int main() {  
    uint8_t key[] = "DeluxeBait";  
    uint8_t s[256];  
    rc4_init(key, s, 10);  
    uint8_t enc_flag[22] = {  
            0xE9, 0x37, 0xF8, 0xE2, 0x0C, 0x0F, 0x3D, 0xB9, 0x5C, 0xA3, 0xDE, 0x2D, 0x55, 0x96, 0xDF, 0xA2,  
            0x35, 0xFE, 0xB3, 0xDD, 0x7F, 0x91  
    };  
    rc4_crypt(s, enc_flag, 22);  
    printf("%s", enc_flag);  
}

但是解出来是假的,找找hook


VirtualProtect 是 Windows 操作系统中的一个 API 函数,用于更改进程中虚拟内存页的保护属性(如读取、写入、执行等)。这个函数通常用于修改进程的内存权限,以便执行某些操作,如修改代码、直接操作内存等。

函数原型:

BOOL VirtualProtect(
  LPVOID lpAddress,   // 指向要更改的内存区域的起始地址
  SIZE_T dwSize,      // 要更改保护属性的内存区域的大小(以字节为单位)
  DWORD  flNewProtect,// 新的保护属性
  PDWORD lpflOldProtect // 返回原来的保护属性
);

参数说明:

  • lpAddress:指向内存区域的起始地址,可以是进程中有效的任何虚拟地址。

  • dwSize:要更改保护的内存区域的大小,单位为字节。即更改保护的内存块的大小。

  • flNewProtect:新设置的内存保护属性。这个参数定义了你希望为该内存区域设置的权限,常见的权限有:

    • PAGE_READONLY:只读权限。
    • PAGE_READWRITE:读写权限。
    • PAGE_EXECUTE:可执行权限。
    • PAGE_EXECUTE_READ:可执行并且可读权限。
    • PAGE_EXECUTE_READWRITE:可执行、可读、可写权限。
    • PAGE_NOACCESS:无访问权限。
    • PAGE_GUARD:启用页面保护,以便防止访问此内存页时触发访问违规。

    还有其他一些特殊的权限标志。

  • lpflOldProtect:指向一个变量,该变量将在函数成功执行时返回原始的内存保护属性。可以通过该值来恢复原来的权限。

返回值:

  • 如果函数成功执行,返回 TRUE
  • 如果函数失败,返回 FALSE,并可以通过 GetLastError 获取错误码。

示例代码:

以下是一个简单的示例,演示如何使用 VirtualProtect 来更改内存区域的保护属性:

#include 
#include 

int main() {
    // 分配内存
    DWORD oldProtect;
    char *data = (char *)VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READWRITE);

    // 修改内存的保护属性,将其设置为只读
    if (VirtualProtect(data, 4096, PAGE_READONLY, &oldProtect)) {
        printf("内存保护属性已更改为只读\n");
    } else {
        printf("更改内存保护属性失败: %lu\n", GetLastError());
    }

    // 恢复原来的内存保护属性
    VirtualProtect(data, 4096, oldProtect, &oldProtect);
    
    // 释放内存
    VirtualFree(data, 0, MEM_RELEASE);
    
    return 0;
}

解释:

  1. 我们首先分配了一块内存,通过 VirtualAlloc 分配 4096 字节,并指定权限为 PAGE_READWRITE(读写权限)。
  2. 然后,我们使用 VirtualProtect 将这块内存的权限更改为 PAGE_READONLY(只读)。更改之前我们保存了原来的权限(通过 oldProtect)。
  3. 最后,我们恢复了原来的权限并释放了这块内存。

使用场景:

  1. 修改内存保护:通常用于动态修改程序的内存区域权限,比如修改代码段、动态执行代码、改变某些内存区域的访问权限等。
  2. 调试/逆向工程:在调试器或逆向工程中,经常需要修改内存保护属性,尤其是在执行代码注入或修改程序行为时。
  3. 防止程序崩溃:例如,操作系统或程序可能希望在某些情况下禁止写入某些内存区域,或者防止代码在特定内存区域执行。

注意事项:

  • 更改内存保护时,如果该内存区域正在被访问,操作系统会触发访问冲突异常。因此,务必确保你对保护的操作是谨慎的,避免意外的崩溃或内存损坏。
  • VirtualProtect 只能更改进程的虚拟内存区域权限,无法直接影响系统或其他进程的内存。

总结来说,VirtualProtect 是一个强大且灵活的函数,能够修改内存的保护属性,在某些场景下非常有用,但使用时需要谨慎,特别是在涉及动态内存操作和安全性时。


我们找一下这个函数的调用

char __fastcall sub_140001C00(void *a1, __int64 a2)
{
    DWORD flOldProtect;  // 用于存储原始的内存保护设置
    // 定义一个数组 `Src`,该数组有两个元素,大小为 16 字节。  
    // 数组用于存放源数据,将来用来覆盖目标内存区域
    _QWORD Src[2];  // [rsp+28h] [rbp-20h] BYREF
    
    // 初始化 `Src[0]` 的低 32 位为 9727(即0x260F),并清空 `Src[0]` 的高 16 位
    LODWORD(Src[0]) = 9727;  
    WORD2(Src[0]) = 0;  

    // 将 `a2` 的值(通常是一个指针或数据值)存储在 `Src` 的第一个元素的高 64 位
    *(_QWORD *)((char *)Src + 6) = a2;  // 将 a2 存储到 `Src[0]` 的高 64 位

    // 使用 `VirtualProtect` 函数更改目标内存区域的保护状态
    // 允许对目标内存区域进行写操作
    VirtualProtect(a1, 0xEuLL, 0x40u, &flOldProtect);  
    // 将 `Src` 数组的内容(长度为 0xE 字节)复制到 `a1` 指向的内存地址
    memcpy(a1, Src, 0xEuLL);  

    // 恢复原来的内存保护设置
    VirtualProtect(a1, 0xEuLL, flOldProtect, &flOldProtect);  

    // 返回 1 表示函数成功执行
    return 1;
}
char sub_7FF759441AD0()
{
    int i;  // 用于循环控制的变量
    int j;  // 用于循环控制的变量
    HMODULE hModule;  // 存储模块句柄
    FARPROC ProcAddress;  // 存储函数地址
    CHAR ProcName[8];  // 存储解码后的函数名
    CHAR ModuleName[16];  // 存储解码后的模块名

    // 将字符串 "fpagqr`v=w" 复制到 ModuleName 中
    qmemcpy(ModuleName, "fpagqr`v=w", 10);
    ModuleName[10] = 127;  // 设置 ModuleName 的第 11 个字符为 127
    ModuleName[11] = 127;  // 设置 ModuleName 的第 12 个字符为 127
    ModuleName[12] = 0;    // 设置 ModuleName 的第 13 个字符为 null 终止符

    // 对 ModuleName 进行解码,解码方式是每个字符与 0x13 进行异或运算
    for (i = 0; i < 12; ++i)
        ModuleName[i] ^= 0x13u;

    // 获取解码后的模块的句柄
    hModule = GetModuleHandleA(ModuleName);

    // 将字符串 "`gap~c" 复制到 ProcName 中
    strcpy(ProcName, "`gap~c");

    // 对 ProcName 进行解码,解码方式是每个字符与 0x13 进行异或运算
    for (j = 0; j < 6; ++j)
        ProcName[j] ^= 0x13u;

    // 获取解码后的函数的地址
    ProcAddress = GetProcAddress(hModule, ProcName);

    // 调用函数 sub_7FF759441C00,传入解码后的函数地址和另一个函数地址
    sub_7FF759441C00(ProcAddress, (__int64)sub_7FF759441CE0);

    // 返回 1,表示函数成功执行
    return 1;
}

GetModuleHandleA() 是一个 Windows API 函数,用于获取指定模块(DLL 或 EXE)的模块句柄。模块句柄是操作系统内部用于标识已加载模块的一个唯一标识符。该函数的声明如下:

HMODULE GetModuleHandleA(LPCSTR lpModuleName);

参数:

  • lpModuleName
    • 类型:LPCSTR(即 const char*),它是一个指向以 null 结尾的字符串,表示要获取句柄的模块的名称。
    • 该参数可以是模块的文件名(例如 "kernel32.dll")或者一个已经加载的模块的名称。如果该参数为空(NULL),则返回当前进程的可执行文件(EXE)的句柄。

返回值:

  • 成功:返回一个 HMODULE(模块句柄),它是一个指向已加载模块的指针。
  • 失败:返回 NULL,并且可以使用 GetLastError() 获取错误信息。

主要用途:

  • GetModuleHandleA 的常见用途是获取某个模块(例如 DLL 或 EXE)的模块句柄,以便后续调用其他 API(例如 GetProcAddress)来获取模块中某个函数的地址,或者用来查询模块的相关信息。

GetModuleHandleAGetModuleHandleW

  • GetModuleHandleA 是 ANSI 版本的函数,它使用 char 类型的字符串(适用于 ASCII 编码)。
  • GetModuleHandleW 是 Unicode 版本的函数,使用 wchar_t 类型的字符串(适用于宽字符编码)。

在 Windows 中,GetModuleHandleA 主要用于处理传统的 ANSI 字符串,而 GetModuleHandleW 则用于支持 Unicode 字符串的情况。

示例代码:

#include 
#include 

int main() {
    // 获取 kernel32.dll 模块句柄
    HMODULE hModule = GetModuleHandleA("kernel32.dll");

    if (hModule != NULL) {
        printf("Module handle: %p\n", hModule);
    } else {
        printf("Failed to get module handle. Error: %lu\n", GetLastError());
    }

    return 0;
}

示例说明:

  • 上面的代码通过 GetModuleHandleA 获取了 kernel32.dll 模块的句柄。如果成功,它将打印出模块的句柄值。如果失败,则会打印错误信息。

注意事项:

  • 如果模块已被加载,GetModuleHandleA 会返回该模块的句柄。如果模块尚未加载,函数将返回 NULL
  • 该函数并不会加载模块,如果指定的模块还没有被加载,它只是返回已经加载的模块的句柄。
  • 如果你希望在模块尚未加载的情况下加载它并获取句柄,可以使用 LoadLibraryALoadLibraryW 函数。

常见用法:

  1. 获取进程的主模块句柄

    • 如果传入的参数为空(NULL),GetModuleHandleA 将返回当前进程的主模块(EXE)的句柄。
  2. 获取已加载的 DLL 的句柄

    • 当你希望获取已经加载的 DLL 模块句柄时,传入 DLL 文件名即可。
  3. 配合 GetProcAddress 获取函数地址

    • 一旦你获取了模块句柄,你可以使用 GetProcAddress 获取该模块内指定函数的地址。

总结:

GetModuleHandleA 是一个非常实用的函数,允许你在不加载模块的情况下,获取已经加载到当前进程的模块的句柄。这对于动态加载库、获取模块信息、API hook 等操作是非常有帮助的。


GetProcAddress

GetProcAddress 是 Windows API 中的一个函数,主要用于动态加载模块时,获取指定模块中某个函数的地址。它在 Windows 系统中广泛用于加载动态链接库(DLL)中的函数。

函数原型

FARPROC GetProcAddress(
  HMODULE hModule,  // 模块的句柄
  LPCSTR  lpProcName // 函数的名称或函数的序号
);

参数说明

  1. hModule

    • 类型:HMODULE(模块句柄)
    • 这是指向已加载模块的句柄。模块可以是一个 DLL 文件或 EXE 文件,通常通过 LoadLibraryGetModuleHandle 函数获取该句柄。
  2. lpProcName

    • 类型:LPCSTR(指向常量字符的指针)
    • 这是要查找的函数名或者是函数的序号。可以传入:
      • 函数名称:这是一个字符串,表示要查找的函数的名称。例如 "CreateFile", "MessageBoxA" 等。
      • 函数序号:可以传递一个整数值,代表函数的序号(位置),而不是通过名称查找。

返回值

  • 成功:返回值是一个 函数的地址,即该函数的入口地址。这个地址是可以调用的,可以通过该地址来执行相应的函数。

  • 失败:如果函数没有找到,返回 NULL。此时,可以调用 GetLastError() 获取详细的错误信息。

使用示例

#include 
#include 

int main() {
    // 加载 User32.dll 模块
    HMODULE hModule = LoadLibrary("user32.dll");
    if (hModule == NULL) {
        printf("Failed to load library\n");
        return -1;
    }

    // 获取 MessageBoxA 函数的地址
    FARPROC pMessageBox = GetProcAddress(hModule, "MessageBoxA");
    if (pMessageBox == NULL) {
        printf("Failed to get proc address\n");
        return -1;
    }

    // 将获取到的函数地址转换为 MessageBox 类型的函数指针
    typedef int (WINAPI *MessageBoxA_t)(HWND, LPCSTR, LPCSTR, UINT);
    MessageBoxA_t MessageBoxA_func = (MessageBoxA_t)pMessageBox;

    // 使用 MessageBoxA 函数进行弹窗
    MessageBoxA_func(NULL, "Hello, World!", "Test", MB_OK);

    // 卸载模块
    FreeLibrary(hModule);

    return 0;
}

解释:

  • 加载模块:使用 LoadLibrary 加载 user32.dll 动态链接库。
  • 获取函数地址:通过 GetProcAddress 获取 user32.dll 中的 MessageBoxA 函数的地址。这个地址就是一个函数指针,可以通过它来调用 MessageBoxA
  • 调用函数:将获取到的地址转换为对应类型的函数指针,并调用 MessageBoxA 显示一个弹窗。

错误处理:

  1. 加载库失败:如果 LoadLibrary 返回 NULL,表示模块加载失败。可以使用 GetLastError() 获取详细错误信息。
  2. 获取函数失败:如果 GetProcAddress 返回 NULL,表示指定的函数在模块中不存在。常见原因包括函数名错误、函数不在当前模块中、或函数未导出。

常见使用场景:

  • 动态链接库(DLL)调用:在程序运行时,通过 GetProcAddress 来动态获取 DLL 中函数的地址,从而调用 DLL 中的函数。这使得程序能够在运行时动态加载不同的模块和函数。

  • 插件系统:很多软件使用插件架构,允许通过 GetProcAddress 来加载并调用插件提供的函数,而不需要在编译时将插件与主程序绑定。

总之,GetProcAddress 允许在运行时动态查找并调用模块中的函数,它对于实现插件机制和动态链接非常有用。


动调发现替换了strcpm为sub_7FF759441CE0

    if ( strcmp(Str1, &Str2) )
      sub_7FF759442FD0("Didn't the fish take the bait?\n", v10, v11);
    else
      sub_7FF759442FD0("Did the fish take the bait?\n", v10, v11);

整理一下

__int64 __fastcall hook(_BYTE *a1, unsigned __int8 *a2)
{
  unsigned int v3; // [rsp+20h] [rbp-108h]
  unsigned int v4; // [rsp+20h] [rbp-108h]
  unsigned int v5; // [rsp+20h] [rbp-108h]
  unsigned int v6; // [rsp+24h] [rbp-104h]
  unsigned int v7; // [rsp+24h] [rbp-104h]
  unsigned int v8; // [rsp+24h] [rbp-104h]
  unsigned int v9; // [rsp+28h] [rbp-100h]
  unsigned int v10; // [rsp+28h] [rbp-100h]
  unsigned int v11; // [rsp+28h] [rbp-100h]
  char v12; // [rsp+2Ch] [rbp-FCh]
  int i; // [rsp+30h] [rbp-F8h]
  int j; // [rsp+34h] [rbp-F4h]
  int ii; // [rsp+38h] [rbp-F0h]
  int jj; // [rsp+3Ch] [rbp-ECh]
  int kk; // [rsp+40h] [rbp-E8h]
  int mm; // [rsp+44h] [rbp-E4h]
  int nn; // [rsp+48h] [rbp-E0h]
  int v20; // [rsp+4Ch] [rbp-DCh]
  int k; // [rsp+50h] [rbp-D8h]
  int m; // [rsp+54h] [rbp-D4h]
  int n; // [rsp+58h] [rbp-D0h]
  HMODULE hModule; // [rsp+60h] [rbp-C8h]
  FARPROC ProcAddress; // [rsp+68h] [rbp-C0h]
  CHAR LibFileName[16]; // [rsp+70h] [rbp-B8h] BYREF
  CHAR ProcName[16]; // [rsp+80h] [rbp-A8h] BYREF
  _BYTE v28[3]; // [rsp+90h] [rbp-98h] BYREF
  char v29[11]; // [rsp+93h] [rbp-95h] BYREF
  char v30[10]; // [rsp+9Eh] [rbp-8Ah] BYREF
  char v31[32]; // [rsp+A8h] [rbp-80h] BYREF
  _DWORD v32[6]; // [rsp+C8h] [rbp-60h] BYREF
  _DWORD enc_input[14]; // [rsp+E0h] [rbp-48h] BYREF
  _BYTE *v34; // [rsp+130h] [rbp+8h]

  v34 = a1;
  memset(v32, 0, 0x14uLL);
  memset(enc_input, 0, 0x32uLL);
  for ( i = 0; i < 20; ++i )
    *((_BYTE *)v32 + i) = a1[i - 80];
  for ( j = 0; j < 50; ++j )
    *((_BYTE *)enc_input + j) = a1[j - 56];
  v3 = 0;
  v6 = enc_input[0];
  v9 = enc_input[1];
  for ( k = 0; k < 24; ++k )
  {
    v6 += (v32[v3 & 3] + v3) ^ (v9 + ((v9 >> 5) ^ (16 * v9)));
    v3 += 1719109785;
    v9 += (v32[(v3 >> 11) & 3] + v3) ^ (v6 + ((v6 >> 5) ^ (16 * v6)));
  }
  enc_input[0] = v6;
  enc_input[1] = v9;
  v4 = 0;
  v7 = enc_input[2];
  v10 = enc_input[3];
  for ( m = 0; m < 24; ++m )
  {
    v7 += (v32[v4 & 3] + v4) ^ (v10 + ((v10 >> 5) ^ (16 * v10)));
    v4 += 1719109785;
    v10 += (v32[(v4 >> 11) & 3] + v4) ^ (v7 + ((v7 >> 5) ^ (16 * v7)));
  }
  enc_input[2] = v7;
  enc_input[3] = v10;
  v5 = 0;
  v8 = enc_input[4];
  v11 = enc_input[5];
  for ( n = 0; n < 24; ++n )
  {
    v8 += (v32[v5 & 3] + v5) ^ (v11 + ((v11 >> 5) ^ (16 * v11)));
    v5 += 1719109785;
    v11 += (v32[(v5 >> 11) & 3] + v5) ^ (v8 + ((v8 >> 5) ^ (16 * v8)));
  }
  enc_input[4] = v8;
  enc_input[5] = v11;
  v12 = 1;
  for ( ii = 0; ii < 24; ++ii )
  {
    if ( enc_flag[ii] != *((unsigned __int8 *)enc_input + ii) )
    {
      v12 = 0;
      break;
    }
  }
  if ( v12 )
  {
    strcpy(LibFileName, "dbtc\"#?u}}");
    for ( jj = 0; jj < 10; ++jj )
      LibFileName[jj] ^= 0x11u;
    hModule = LoadLibraryA(LibFileName);
    strcpy(ProcName, "\\tbbpvtS~iP");
    for ( kk = 0; kk < 11; ++kk )
      ProcName[kk] ^= 0x11u;
    ProcAddress = GetProcAddress(hModule, ProcName);
    strcpy(v31, "H~d6gt1rpdvye1p1sxv1wxby0");
    for ( mm = 0; mm < 25; ++mm )
      v31[mm] ^= 0x11u;
    qmemcpy(v28, "R~", 2);
    v28[2] = 127;
    qmemcpy(v29, "vcped}pex~", 10);
    v29[10] = 127;
    strcpy(v30, "000");
    for ( nn = 0; nn < 17; ++nn )
      v28[nn] ^= 0x11u;
    ((void (__fastcall *)(_QWORD, char *, _BYTE *, _QWORD))ProcAddress)(0LL, v31, v28, 0LL);
  }
  while ( 1 )
  {
    v20 = (unsigned __int8)*v34 - *a2;
    if ( v20 || !*v34 )
      break;
    ++v34;
    ++a2;
  }
  if ( v20 > 0 )
    return 1LL;
  if ( v20 >= 0 )
    return 0LL;
  return 0xFFFFFFFFLL;
}

xtea

#define num_rounds 24  
#define delta 0x66778899

void xtea_decrypt(uint32_t v[2], uint32_t const key[4]) {  
    uint32_t i;  
    uint32_t v0 = v[0], v1 = v[1], sum = delta*num_rounds;  
    for (i = 0; i < num_rounds; i++) {  
        // v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);  
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);  
        sum -= delta;  
        // v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);  
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);  
    }  
    v[0] = v0; v[1] = v1;  
}

int main()  
{  
    uint8_t Key[] = "DeluxeBait\0\0\0\0\0\0";  
  
    uint32_t enc_flag_1[] = {  
            0xA6975621, 0xDEC4D51A  
    };  
    xtea_decrypt(enc_flag_1, (uint32_t*)Key);  
    uint32_t enc_flag_2[] = {  
            0x4D829CA4, 0x56C845D1,  
    };  
    xtea_decrypt(enc_flag_2, (uint32_t*)Key);  
    uint32_t enc_flag_3[] = {  
            0x5C96B4A7, 0x2087494D  
    };  
    xtea_decrypt(enc_flag_3, (uint32_t*)Key);  
  
    printf("%.8s%.8s%.8s", enc_flag_1, enc_flag_2, enc_flag_3);  
    return 0;  
}

网站公告

今日签到

点亮在社区的每一天
去签到