分析主函数
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;
}
解释:
- 我们首先分配了一块内存,通过
VirtualAlloc
分配 4096 字节,并指定权限为PAGE_READWRITE
(读写权限)。 - 然后,我们使用
VirtualProtect
将这块内存的权限更改为PAGE_READONLY
(只读)。更改之前我们保存了原来的权限(通过oldProtect
)。 - 最后,我们恢复了原来的权限并释放了这块内存。
使用场景:
- 修改内存保护:通常用于动态修改程序的内存区域权限,比如修改代码段、动态执行代码、改变某些内存区域的访问权限等。
- 调试/逆向工程:在调试器或逆向工程中,经常需要修改内存保护属性,尤其是在执行代码注入或修改程序行为时。
- 防止程序崩溃:例如,操作系统或程序可能希望在某些情况下禁止写入某些内存区域,或者防止代码在特定内存区域执行。
注意事项:
- 更改内存保护时,如果该内存区域正在被访问,操作系统会触发访问冲突异常。因此,务必确保你对保护的操作是谨慎的,避免意外的崩溃或内存损坏。
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
)来获取模块中某个函数的地址,或者用来查询模块的相关信息。
GetModuleHandleA
与 GetModuleHandleW
:
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
。 - 该函数并不会加载模块,如果指定的模块还没有被加载,它只是返回已经加载的模块的句柄。
- 如果你希望在模块尚未加载的情况下加载它并获取句柄,可以使用
LoadLibraryA
或LoadLibraryW
函数。
常见用法:
获取进程的主模块句柄:
- 如果传入的参数为空(
NULL
),GetModuleHandleA
将返回当前进程的主模块(EXE)的句柄。
- 如果传入的参数为空(
获取已加载的 DLL 的句柄:
- 当你希望获取已经加载的 DLL 模块句柄时,传入 DLL 文件名即可。
配合
GetProcAddress
获取函数地址:- 一旦你获取了模块句柄,你可以使用
GetProcAddress
获取该模块内指定函数的地址。
- 一旦你获取了模块句柄,你可以使用
总结:
GetModuleHandleA
是一个非常实用的函数,允许你在不加载模块的情况下,获取已经加载到当前进程的模块的句柄。这对于动态加载库、获取模块信息、API hook 等操作是非常有帮助的。
GetProcAddress
GetProcAddress
是 Windows API 中的一个函数,主要用于动态加载模块时,获取指定模块中某个函数的地址。它在 Windows 系统中广泛用于加载动态链接库(DLL)中的函数。
函数原型
FARPROC GetProcAddress(
HMODULE hModule, // 模块的句柄
LPCSTR lpProcName // 函数的名称或函数的序号
);
参数说明
hModule
:- 类型:
HMODULE
(模块句柄) - 这是指向已加载模块的句柄。模块可以是一个 DLL 文件或 EXE 文件,通常通过
LoadLibrary
或GetModuleHandle
函数获取该句柄。
- 类型:
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
显示一个弹窗。
错误处理:
- 加载库失败:如果
LoadLibrary
返回NULL
,表示模块加载失败。可以使用GetLastError()
获取详细错误信息。 - 获取函数失败:如果
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;
}