boxmoe_header_banner_img

欢迎来到烨的世界~

加载中

文章导读

iscc-re-2024


avatar
liuye 2025年4月28日 59

WEEK1-reverse4_DLLCode

看了exe和dll都没有加壳

然后直接ida

dp跟我说这就是引用了dll之类的第三方所以没办法知道函数名

恰好题目用了dll

我们去看一下dll这个函数是什么

算了先不看,先把主程序看完

主要校验

v8有24个恰好和flag个数一样有可能是校验值或者密文?

这是exe的主函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
char *v4; // eax
_DWORD *v5; // eax
int v6; // eax
int v7; // [esp-4h] [ebp-13Ch]
int v8[24]; // [esp+Ch] [ebp-12Ch] BYREF
char v9[4]; // [esp+6Ch] [ebp-CCh] BYREF
int v10; // [esp+70h] [ebp-C8h]
char v11; // [esp+7Bh] [ebp-BDh] BYREF
unsigned int i; // [esp+7Ch] [ebp-BCh]
char v13[24]; // [esp+80h] [ebp-B8h] BYREF
char v14[24]; // [esp+98h] [ebp-A0h] BYREF
char v15[24]; // [esp+B0h] [ebp-88h] BYREF
char v16[24]; // [esp+C8h] [ebp-70h] BYREF
char v17[24]; // [esp+E0h] [ebp-58h] BYREF
int v18[6]; // [esp+F8h] [ebp-40h] BYREF
char v19[12]; // [esp+110h] [ebp-28h] BYREF
char v20[12]; // [esp+11Ch] [ebp-1Ch] BYREF
int v21; // [esp+134h] [ebp-4h]

sub_2C1F40(v18); // 感觉是初始化
v21 = 0;
printf(std::cout, (int)"Please enter a string of 24 lengthss:");
scanf(std::cin, v18);
if ( unknown_libname_5(v18) == 24 )
{
sub_2C1F40(v16);
LOBYTE(v21) = 1;
sub_2C1F40(v17);
LOBYTE(v21) = 2;
for ( i = 0; i < unknown_libname_5(v18); ++i )
{
v4 = (char *)sub_2C1E70(i);
std::string::operator+=(*v4);
}
Encode(v13, v16);
LOBYTE(v21) = 3;
sub_2C14D0(v14, v17);
LOBYTE(v21) = 4;
sub_2C2DA0(v15, v13, v14); // v13可能是密文?函数进去取了长度,太乱了
LOBYTE(v21) = 5;
sub_2C16A0(0xCu);
v8[0] = 0;
v8[1] = 16;
v8[2] = 56;
v8[3] = 19;
v8[4] = 10;
v8[5] = 61;
v8[6] = 116;
v8[7] = 43;
v8[8] = 3;
v8[9] = 0;
v8[10] = 20;
v8[11] = 3; // 校验或者密文
v8[12] = 67;
v8[13] = 89;
v8[14] = 83;
v8[15] = 68;
v8[16] = 70;
v8[17] = 84;
v8[18] = 64;
v8[19] = 103;
v8[20] = 75;
v8[21] = 125;
v8[22] = 117;
v8[23] = 98;
v7 = unknown_libname_4(&v11);
v5 = (_DWORD *)unknown_libname_3(v8, v9);
sub_2C1D70(*v5, v5[1], v7);
LOBYTE(v21) = 6;
sub_2C16A0(0xCu);
sub_2C15C0(v20, v15);
LOBYTE(v21) = 7;
if ( (unsigned __int8)sub_2C16C0(v20, v19) )
v6 = printf(std::cout, (int)"right!");
else // 最终比较
v6 = printf(std::cout, (int)"error!");
std::ostream::operator<<(v6, sub_2C2E30);
system("pause");
v10 = 0;
LOBYTE(v21) = 6;
sub_2C1CA0(v20);
LOBYTE(v21) = 5;
sub_2C1CA0(v19);
LOBYTE(v21) = 4;
std::string::~string(v15);
LOBYTE(v21) = 3;
std::string::~string(v14);
LOBYTE(v21) = 2;
std::string::~string(v13);
LOBYTE(v21) = 1;
std::string::~string(v17);
LOBYTE(v21) = 0;
std::string::~string(v16);
v21 = -1;
std::string::~string(v18);
return v10;
}
else
{
printf(std::cout, (int)"The input length is incorrect.\n");
v21 = -1;
std::string::~string(v18);
return 1;
}
}

这个主函数在这了,下来去看一下dll

我靠我想了半天我以为 unknown_libname_5这个函数是dll导入我到dll找了半天没找到

直到我去查了…..

​​颜色​​	​​类型/含义​​	​​示例或场景​​	​​备注​​
​​白色​​ ​​普通用户函数​​ 用户编写的函数,如 sub_401000 名称通常以 sub_ 开头,未被识别为库函数或系统函数。

​​蓝色​​ ​​标准库函数​​(通过 FLIRT 签名识别) strcpy, memcmp, std::string::operator+= 名称由 IDA 自动解析,代码逻辑通常被标记为库代码。

​​粉色/紫色​​ ​​导入函数​​(从外部 DLL 导入) KERNEL32.GetProcAddress, USER32.MessageBoxA 函数名格式为 DLL名.函数名,代码通常为 jmp [IAT地址]。

​​浅蓝色​​ ​​Thunk 函数​​(间接跳转函数) thunk_SomeFunction 代码简短(如 jmp ds:SomeFunction),用于跳转到实际函数地址。

​​黄色​​ ​​未分析的代码段​​ 未被 IDA 自动识别为函数的代码区域(可能误判为数据) 需手动按 C 键转换为代码,或按 P 键创建函数。

​​灰色​​ ​​数据区域​​ 全局变量、常量数组、字符串等 非可执行代码,如 db 'Hello World',0。

​​绿色​​ ​​编译器生成的辅助函数​​ 异常处理函数(__ehhandler)、静态初始化函数(_GLOBAL__sub_I_main) 通常由编译器自动生成,用户无需直接调用。
​​橙色​​ ​​外部库函数​​(非标准库) 第三方库函数(如 OpenSSL_SSL_write) 需手动加载对应 FLIRT 签名或通过上下文分析识别。

​​红色​​ ​​标记为无效或冲突的函数​​ IDA 分析过程中发现矛盾的代码(如跳转到非法地址) 需手动修复分析或调整反汇编逻辑。

​​深紫色​​ ​​虚函数表(VTable)引用​​ C++ 类的虚函数表指针(如 vtable_MyClass) 通常与 C++ 对象相关,指向虚函数地址列表。

这家伙是蓝的………

如何我才反应过来

这个encode才是真正的加密函数

去dll找到encode

记录数值了~

ok我看懂了

这傻逼题目的flag是24位

分为前12和后12进行分别加密

前十二位在主函数里加密的

后十二位在dll中加密

前十二位用的加密异或值是v4

后十二位是block

block的值就是ISCC

Block = [73, 83, 67, 67]

后十二加密逻辑是用十二位输入和block进行4次一循环异或

那么开始看前12位

我靠我无语死了前十二位找半天

这里~终于分析完了

我给批注了逻辑应该是很清晰了

所以找前12个加密逻辑直接进入sub_2C14D0

好了找到v4也就是异或值了

上exp

Block = [73, 83, 67, 67]
v4 = [2, 0, 3, 1, 6, 4, 7, 5, 10, 8, 11, 9]
enc = [] #密文
enc_back = enc[:12]
enc_front = enc[12:]
flag = [0] * 24
for i in range(12):
flag[2 * i + 1] = enc_front[v4[i]]
for i in range(12):
enc_back[i] ^= Block[i & 3]
for i in range(12):
flag[2 * i] = enc_back[i]
print(”.join(chr(x) for x in flag))

这里的密文就是v8的值直接输进去就好了

完结撒花!

其实还有第二题…..

mobile1_ChallengeMobile

到手是一个apk

通过分析应用程序的源代码,发现了一个需要解密的函数,但是没有找到正确的密钥。你使用 Jadx 打开了该应用的 dex 文件,发现其中包含了一个名为 Checker 的加密函数,它明显是使用 xxtea 加密算法加密的。为了找到正确的密钥,你编写了 Frida 脚本来 hook getkey 函数,成功获取了需要的密钥。最终,你使用这个密钥成功解密了数据,得到了 flag

exp1
import hashlib
from itertools import product
from string import digits
def get_sha256(s):
return hashlib.sha256(s.encode('utf-8')).hexdigest()
for digits in product(digits, repeat=8):
guess = ''.join(digits) + "gwC9nOCNUhsHqZm"
digest = get_sha256(guess)
if digest ==
'437414687cecdd3526281d4bc6492f3931574036943597fddd40adfbe07a9afa':
print(digest)
print('found', guess)
break

exp2
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Random;
public class App {
private static String combineStrings(String arg1, String arg2) {
return arg1 + arg2;
}
private static byte[] customEncrypt(byte[] arg4, byte[] arg5) {
byte[] v0 = new byte[arg4.length];
int v1;
for(v1 = 0; v1 < arg4.length; ++v1) {
v0[v1] = (byte)(arg4[v1] ^ arg5[v1 % arg5.length]);
}
return v0;
}
public static String encrypt(String arg3, String arg4) {
byte[] v0 = generateSalt(16);
byte[] v3 = customEncrypt(combineStrings(arg3,
arg4).getBytes(StandardCharsets.UTF_8), v0);
byte[] v4 = new byte[v0.length + v3.length];
System.arraycopy(v0, 0, v4, 0, v0.length);
System.arraycopy(v3, 0, v4, v0.length, v3.length);
return Base64.getEncoder().encodeToString(v4);
}
public static String encrypt2(String arg3) {
byte[] v3 = arg3.getBytes(StandardCharsets.UTF_8);
int v0 = 0;
int v1;
for(v1 = 0; v1 < v3.length; ++v1) {
v3[v1] = (byte)((v3[v1] + 0x7F) % 0x100);
}
byte[] v1_1 = new byte[v3.length];
while(v0 < v3.length) {
v1_1[v0] = (byte)(v0 % 2 == 0 ? v3[v0] ^ 0x7B : v3[v0] ^ 0xEA);
++v0;
}
return Base64.getEncoder().encodeToString(v1_1);
}
private static byte[] generateSalt(int i) {
byte[] bArr = new byte[i];
new Random(3452L).nextBytes(bArr);
return bArr;
}
public static void main(String[] args) {
System.out.println("ISCC{"+encrypt2(encrypt("04999999",
"gwC9nOCNUhsHqZm")).substring(0, 32)+"}");
}
}

ok复现不出来不会用frida来hook

hide_and_seek

找到对应位置

下断点然后运行直接到断点改zf寄存器

直接改成1

然后点继续运行就好

不管他这边已经改过zf了

然后搜索text

直接找ctf就找到了

ok发文



评论(0)

查看评论列表

暂无评论


发表评论