送分题
关注公众号
解题领红包之二 {Windows 初级题}(初二 2/11 10:00 上线)
动调直接拿
fl@g{H@ppy_N3w_e@r!2o24!Fighting!!!}
【春节】解题领红包之三 {Android 初级题}(初三 2/12 10:00 上线)
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.io.RandomAccessFile;
//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
public static String extractDataFromFile(String p0){
int i;
try{
RandomAccessFile randomAccess = new RandomAccessFile(p0, "r");
long l = randomAccess.length();
p0 = "flag{";
long l1 = Math.max((l - (long)30), 0);
while (true) {
if ((l1 - l) < 0) {
randomAccess.seek(l1);
byte[] uobyteArray = new byte[30];
randomAccess.read(uobyteArray);
String str = new String(uobyteArray, StandardCharsets.UTF_8);
if ((i = str.indexOf(p0)) != -1) {
randomAccess.close();
return str.substring(i).split("\\}")[0]+"}";
}else {
l1 = l1 + 1;
}
}else {
randomAccess.close();
break ;
}
}
}catch(java.lang.Exception e9){
e9.printStackTrace();
}
return null;
}
public static void main(String[] args) {
String filePath = "xxx\\xxx\\xxx\\ys.mp4"; //你的路径
System.out.println(extractDataFromFile(filePath));
}
}
运行就是flag
flag{happy_new_year_2024}
当然可以看到字符串是明文存储,直接010看也可以
【春节】解题领红包之四 {Android 初级题}(初四 2/13 10:00 上线)
2
这里要到FlagActivity里面去,一开始准备是修改跳转,直接进的。发现是获取签名进行异或,
这里换一下思路,启动FlagActivity就好
adb shell am start -n com.kbtx.redpack_simple/.FlagActivity
3
【2024春节】解题领红包之五 {Android 中级题}
审计代码后发现有个dex修复
我添加调试之后,调试总是异常。
后面纯纯脑洞题
package com.zj.wuaipojie2024_2;
import android.content.Context;
import android.util.Log;
import dalvik.system.DexClassLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.HashMap;
public class C {
public static final String SIGNATURE = "fe4f4cec5de8e8cf2fca60a4e61f67bcd3036117";
private static final String TAG = "ZJ595";
private static File fix(ByteBuffer byteBuffer0, int v, int v1, int v2, Context context0) throws Exception {
try {
File file0 = context0.getDir("data", 0);
int v3 = (int)(((Integer)D.getClassDefData(byteBuffer0, v).get("class_data_off")));
HashMap hashMap0 = D.getClassData(byteBuffer0, v3);
((int[][])hashMap0.get("direct_methods"))[v1][2] = v2;
byte[] arr_b = D.encodeClassData(hashMap0);
byteBuffer0.position(v3);
byteBuffer0.put(arr_b);
byteBuffer0.position(0x20);
byte[] arr_b1 = new byte[byteBuffer0.capacity() - 0x20];
byteBuffer0.get(arr_b1);
byte[] arr_b2 = Utils.getSha1(arr_b1);
byteBuffer0.position(12);
byteBuffer0.put(arr_b2);
int v4 = Utils.checksum(byteBuffer0);
byteBuffer0.position(8);
byteBuffer0.putInt(Integer.reverseBytes(v4));
byte[] arr_b3 = byteBuffer0.array();
File file1 = new File(file0, "2.dex");
FileOutputStream fileOutputStream0 = new FileOutputStream(file1);
fileOutputStream0.write(arr_b3);
fileOutputStream0.close();
return file1;
}
catch(Exception exception0) {
exception0.printStackTrace();
return null;
}
}
private static Method getStaticMethod(Context context0, int[] arr_v, String s, String s1, Class[] arr_class) throws Exception {
try {
File file0 = C.fix(C.read(context0), arr_v[0], arr_v[1], arr_v[2], context0);
ClassLoader classLoader0 = context0.getClass().getClassLoader();
File file1 = context0.getDir("fixed", 0);
Method method0 = new DexClassLoader(file0.getAbsolutePath(), file1.getAbsolutePath(), null, classLoader0).loadClass(s).getDeclaredMethod(s1, arr_class);
file0.delete();
new File(file1, file0.getName()).delete();
return method0;
}
catch(Exception exception0) {
exception0.printStackTrace();
return null;
}
}
public static String isValidate(Context context0, String s, int[] arr_v) throws Exception {
try {
return (String)C.getStaticMethod(context0, arr_v, "com.zj.wuaipojie2024_2.A", "d", new Class[]{Context.class, String.class}).invoke(null, context0, s);
}
catch(Exception exception0) {
Log.e("ZJ595", "咦,似乎是坏掉的dex呢!");
exception0.printStackTrace();
return "";
}
}
private static ByteBuffer read(Context context0) {
try {
File file0 = new File(context0.getDir("data", 0), "decode.dex");
if(!file0.exists()) {
return null;
}
FileInputStream fileInputStream0 = new FileInputStream(file0);
byte[] arr_b = new byte[fileInputStream0.available()];
fileInputStream0.read(arr_b);
ByteBuffer byteBuffer0 = ByteBuffer.wrap(arr_b);
fileInputStream0.close();
return byteBuffer0;
}
catch(Exception unused_ex) {
return null;
}
}
}
这里先把a的数组值找出来
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="A_offset">
<item>@null</item>
<item>3</item>
<item>7908</item>
</array>
<array name="B_offset">
<item>1</item>
<item>1</item>
<item>8108</item>
</array>
</resources>
这里解部分dex,获取关键代码
这里解密的dex名称是1.dex
4
解密dex
打断点,这里先运行完,直接adb 拉出来
关键代码
public static String d(Context context0, String s) {
MainActivity.sSS(s);
String s1 = Utils.getSignInfo(context0);
if(s1 != null && (s1.equals("fe4f4cec5de8e8cf2fca60a4e61f67bcd3036117"))) {
StringBuffer stringBuffer0 = new StringBuffer();
for(int v = 0; stringBuffer0.length() < 9 && v < 40; ++v) {
String s2 = "0485312670fb07047ebd2f19b91e1c5f".substring(v, v + 1);
if(!stringBuffer0.toString().contains(s2)) {
stringBuffer0.append(s2);
}
}
return s.equals(stringBuffer0.toString().toUpperCase()) ? "唉!哪有什么亿载沉睡的玄天帝,不过是一位被诅咒束缚的旧日之尊,在灯枯之际挣扎的南柯一梦罢了。有缘人,这份机缘就赠予你了。坐标在B.d" : "";
}
return "";
}
看情况要解密B
我先解出来密码
StringBuffer stringBuffer0 = new StringBuffer();
for(int v = 0; stringBuffer0.length() < 9 && v < 40; ++v) {
String s2 = "0485312670fb07047ebd2f19b91e1c5f".substring(v, v + 1);
if(!stringBuffer0.toString().contains(s2)) {
stringBuffer0.append(s2);
}
}//048531267
System.out.println(stringBuffer0.toString().toUpperCase());
密码就是048531267
解密完B
package com.zj.wuaipojie2024_2;
public class B {
public static String d(String s) {
return "机缘是{" + Utils.md5(Utils.getSha1("password+你的uid".getBytes())) + "}";
}
}
把自己论坛id加上去跑一下就行。
【春节】解题领红包之六 {Windows 高级题}(初六 2/15 10:00 上线)
客户端
crackme2024 upx壳,抹去upx信息,只能手脱
oep=00000001400038DC
int __cdecl main(int argc, const char **argv, const char **envp)
{
HANDLE StdHandle; // rdi
__int64 uid; // rcx
unsigned __int64 v7; // rax
char *EndPtr; // [rsp+50h] [rbp-138h] BYREF
unsigned int v10; // [rsp+58h] [rbp-130h] BYREF
char serial[272]; // [rsp+60h] [rbp-128h] BYREF
printf_s("%s @ www.52pojie.cn\n", &ConsoleTitle);
onexit(Func);
SetConsoleTitleA(&ConsoleTitle);
printf("Happy New Year!\nAuthor: solly\n\n");
v10 = 0;
memset(serial, 0, 0x104ui64);
StdHandle = GetStdHandle(0xFFFFFFF5);
if ( argc <= 3 )
{
printf(" Enter your uid: ");
scanf_s("%lu", &v10);
uid = v10;
if ( v10 )
{
printf("Enter your serial: ");
scanf_s("%s", serial);
uid = v10;
}
}
else
{
v10 = strtoul(argv[1], &EndPtr, 10);
memcpy_s(serial, 0x24ui64, argv[2], 0x104ui64);
uid = v10;
}
if ( !(_DWORD)uid )
goto LABEL_12;
v7 = -1i64;
do
++v7;
while ( serial[v7] );
if ( v7 >= 0x23 )
{
if ( (unsigned __int8)check(uid, serial) )
{
printf("\nChecking result: ");
SetConsoleTextAttribute(StdHandle, 9u);
printf("SUCCESS. ");
SetConsoleTextAttribute(StdHandle, 7u);
printf("Congratulations!!\n\n");
printf("You can run crackme2024service.exe /UnregServer as administrator to unload the server.\n");
}
else
{
printf("\nChecking result: ");
SetConsoleTextAttribute(StdHandle, 0xCu);
printf("FAILURE. ");
SetConsoleTextAttribute(StdHandle, 7u);
printf("Try it again!!!!!\n\n");
}
}
else
{
LABEL_12:
printf("\nERROR: uid or serial is error\n");
}
return 0;
}
审计之后发现我们的uid和序列号 到check里面了
__int64 __fastcall check(unsigned int uid, const char *serial)
{
LPVOID ppv; // [rsp+30h] [rbp-F8h] BYREF
char v6[8]; // [rsp+38h] [rbp-F0h] BYREF
char Destination[208]; // [rsp+40h] [rbp-E8h] BYREF
v6[0] = 0;
qword_140020E50 = (unsigned __int8)sub_1400022F0(346i64, 56i64, 0i64);
if ( CoInitialize(0i64) >= 0 )
{
if ( CoCreateInstance(&rclsid, 0i64, 0x14u, &riid, &ppv) < 0 )
{
printf("\nCreate Server Instance failure. Please run crackme2024service.exe /RegServer as administrator first.\n");
}
else
{
memset(Destination, 0, 0xC8ui64);
strcpy_s(Destination, 0xC8ui64, serial);
(*(void (__fastcall **)(LPVOID, _QWORD))(*(_QWORD *)ppv + 56i64))(ppv, uid);
if ( *(_QWORD *)lpBaseAddress )
*(_QWORD *)lpBaseAddress = (*(__int64 (__fastcall **)(_QWORD))lpBaseAddress)(*((unsigned int *)lpBaseAddress + 2));
(*(void (__fastcall **)(LPVOID, char *))(*(_QWORD *)ppv + 64i64))(ppv, Destination);
if ( (*(unsigned int (__fastcall **)(LPVOID, char *))(*(_QWORD *)ppv + 72i64))(ppv, v6) == 1 )
{
v6[0] = 0;
printf("Running failure. Please run crackme2024service.exe /RegServer as administrator first.\n");
}
(*(void (__fastcall **)(LPVOID))(*(_QWORD *)ppv + 16i64))(ppv);
}
}
CoUninitialize();
return (unsigned __int8)v6[0];
}
调试爆异常看到反调试了,先把反调试处理了
_BOOL8 sub_140002350()
{
struct _PEB *v0; // rax
v0 = NtCurrentPeb();
return v0->BeingDebugged || LOBYTE(v0->NtGlobalFlag) == 112;
}
服务端
找服务端,https://github.com/ergrelet/unlicense/releases/tag/0.4.0 脱壳
sub_401B50 初始化函数有反调试,还有反调试,同理处理patch为,mov eax,0
uid接收函数
void __stdcall sub_401280(_DWORD *a1, int a2)
{
*(_DWORD *)(a1[60] + a1[3] + 8) = a2;
a1[4] = 0;
a1[5] = 0;
}
serical接收函数
这里主要就是格式
int __stdcall sub_4012B0(_DWORD *a1, char *Str)
{
const char *v2; // edi
unsigned int *v3; // ebx
int v4; // ebp
char *i; // esi
unsigned int v6; // eax
_DWORD *v7; // ecx
char *EndPtr; // [esp+14h] [ebp-8h] BYREF
v2 = Str;
v3 = a1 + 6;
memset(a1 + 6, 0, 0xC8u);
v4 = 0;
for ( i = strstr(Str, asc_418F50); i; i = strstr(i + 1, asc_418F50) )
{
*i = 0;
v6 = strtoul(v2, &EndPtr, 16);
v2 = i + 1;
*v3 = v6;
++v4;
++v3;
}
a1[v4 + 6] = strtoul(v2, &EndPtr, 16);
v7 = (_DWORD *)a1[3];
a1[4] = *v7;
a1[5] = v7[1];
return 0;
}
check函数
do
{
v5 = *(_DWORD *)v3;
v6 = &data1[17];
v7 = *((_DWORD *)v3 + 1);
do
{
v8 = *v6--;
v9 = v5 ^ (BeingDebugged + v8);
v5 = v7 ^ (data2[HIBYTE(v9) + 768]
+ (data2[BYTE2(v9) + 512] ^ (data2[(unsigned __int8)v9] + data2[BYTE1(v9) + 256])));
v7 = v9;
}
while ( (int)v6 >= (int)&data1[2] );
v10 = v5 ^ data1[1];
v11 = v9 ^ data1[0];
*((_DWORD *)v3 + 1) = v10;
*(_DWORD *)v3 = v11;
v3 += 8;
--v4;
}
while ( v4 );
LOBYTE(v16) = 0;
*a2 = v14 == _strtoui64(String, 0, 16);
dump出data1和data2数据即可
先模拟算法
_DWORD input[] = { 0x00111111, 0x00111111, 0x00111111, 0x00111111, };
//111111-111111-111111-111111-111111
int v5;
int v7;
_DWORD v9;
for (int i = 0; i < 2; i++)
{
v5 = input[i * 2];
v7 = input[i * 2 + 1];
for (int j = 17; j >= 2; j--)
{
v9 = v5 ^ (data1[j]);
v5 = v7 ^ (data2[HIBYTE(v9) + 768]+ (data2[BYTE2(v9) + 512] ^ (data2[(unsigned __int8)v9] + data2[BYTE1(v9) + 256])));
v7 = v9;
}
input[i * 2+1] = v5^data1[1];
input[i * 2] = v9 ^ data1[0];
}
_DWORD input[] = { 0x00111111, 0x00111111, 0x00111111, 0x00111111, };
//111111-111111-111111-111111-111111
int v5;
int v7;
_DWORD v9;
for (int i = 0; i < 2; i++)
{
v5 = input[i * 2];
v7 = input[i * 2 + 1];
for (int j = 17; j >= 2; j--)
{
v9 = v5 ^ (data1[j]);
v5 = v7 ^ (data2[HIBYTE(v9) + 768]+ (data2[BYTE2(v9) + 512] ^ (data2[(unsigned __int8)v9] + data2[BYTE1(v9) + 256])));
v7 = v9;
}
input[i * 2+1] = v5^data1[1];
input[i * 2] = v9 ^ data1[0];
}
逆向脚本
_DWORD enc[4] = { 0x0D65ACCB, 0xF7C1225A, 0x0D65ACCB, 0xF7C1225A };
for (int i = 0; i < 2; i++)
{
v9 = enc[i * 2] ^ data1[0];
v5 = enc[i * 2 + 1] ^ data1[1];
for (int j = 17; j >= 2; j--)
{
v7= v5^(data2[HIBYTE(v9) + 768] + (data2[BYTE2(v9) + 512] ^ (data2[(unsigned __int8)v9] + data2[BYTE1(v9) + 256])));
v5 = v9 ^ data1[j];
v9 = v7;
}
enc[i * 2] = v5;
enc[i * 2+1] = v7;
}
如果调试过来,密文会变,可能哪里有检测,直接在这里下断点
这里我推测是对uid**3 再跟solly202 进行异或生成的密文
获取密文后,恢复顺序
s='3BE4F544EB760266'
a=[]
for i in range(0,len(s),2):
x=s[i:i+2]
a.append(x)
b=''.join(i for i in a[::-1])
print(b)
#660276EB44F5E43B
然后逆一下算法
char String[] = "660276EB44F5E43B";
_DWORD* enc = (_DWORD*)&String;
//_DWORD enc[4] = { 0x0019F3E4, 0x0019F42C, 0x0019F5D0, 0x767D0E90 };
for (int i = 0; i < 2; i++)
{
v9 = enc[i * 2] ^ data1[0];
v5 = enc[i * 2 + 1] ^ data1[1];
for (int j = 2; j<=17; j++)
{
v7= v5^(data2[HIBYTE(v9) + 768] + (data2[BYTE2(v9) + 512] ^ (data2[(unsigned __int8)v9] + data2[BYTE1(v9) + 256])));
v5 = v9 ^ data1[j];
v9 = v7;
}
enc[i * 2] = v5;
enc[i * 2+1] = v7;
}
def get(s):
z=s.split(' ')
z_=''
for i in range(0,len(z),4):
z_+=''.join(i for i in z[i:i+4][::-1])+'-'
z_=z_[:-1]
print(z_)
#125413ff-936888ec-88eae67e-bd9bb1c7
s='ff 13 54 12 ec 88 68 93 7e e6 ea 88 c7 b1 9b bd'
get(s)