自己做的网站能卖么,网络服务通知,什么都不懂能做电商吗,怎么提高seo排名REVERSE-PRACTICE-JarvisOJ-2DD - HelloAPK_500DebugMeFindPassDD - Hello
macos文件#xff0c;无壳#xff0c;ida分析 start函数和sub_100000C90函数没什么作用 主要的逻辑在sub_100000CE0函数#xff0c;反调试检测和byte_100001040数组的循环变换#xff0c;最后打印…
REVERSE-PRACTICE-JarvisOJ-2DD - HelloAPK_500DebugMeFindPassDD - Hello
macos文件无壳ida分析 start函数和sub_100000C90函数没什么作用 主要的逻辑在sub_100000CE0函数反调试检测和byte_100001040数组的循环变换最后打印flag 按sub_100000CE0函数的逻辑写脚本即可得到flag
byte_100001040[0x41, 0x10, 0x11, 0x11, 0x1B, 0x0A, 0x64, 0x67, 0x6A, 0x68,0x62, 0x68, 0x6E, 0x67, 0x68, 0x6B, 0x62, 0x3D, 0x65, 0x6A,0x6A, 0x3D, 0x68, 0x04, 0x05, 0x08, 0x03, 0x02, 0x02, 0x55,0x08, 0x5D, 0x61, 0x55, 0x0A, 0x5F, 0x0D, 0x5D, 0x61, 0x32,0x17, 0x1D, 0x19, 0x1F, 0x18, 0x20, 0x04, 0x02, 0x12, 0x16,0x1E, 0x54, 0x20, 0x13, 0x14]
start(0x0000000100000CB0)0xff
sub_100000C90(0x0000000100000C90)0xff
v2 ((start - sub_100000C90) 2) ^ byte_100001040[0]
v10
while v155:byte_100001040[v1]-2byte_100001040[v1]^v2v11v21
print(.join(chr(byte_100001040[i]) for i in range(1,len(byte_100001040))))
#DDCTF-5943293119a845e9bbdbde5a369c1f50didichuxing.comAPK_500
apk文件jadx-gui打开 在com.ctf.test.android_ctf_500_test.MainActivity中看到静态加载了easy库输入password后调用easy库中的helloworld函数验证输入 ApkToolBox反编译apk文件后ida打开CTF_500\lib\armeabi-v7a\libeasy.so 没有直接在左侧函数窗找到helloworld函数来到JNI_OnLoad函数 解出三段字符串分别为函数名函数的参数以及函数所在的类 往下走sub_1198函数为验证输入的password 对输入的password有以下几步变换 输入的字符转成了十六进制数 input[i]^i输入和其下标异或 input[i]1i∈[0,3]前4个字节加1 input的前7个字节按原来的顺序放到最后7个位置上其余的字节依次向前移动 变换位置后的input与byte_4004异或 input再转成十六进制数但是不会填充两位例如 “0x0c”-“0xc”有一个0被忽略了 最后input和v50比较
bool __fastcall sub_1198(JNIEnv *a1)
{const char *input; // r4__pid_t v2; // r0int v3; // r3int v4; // r3char *v5; // r2int *v6; // r3int v7; // r0int v8; // r1_BYTE *v9; // lr__pid_t v10; // r0int v11; // r9const char *input_; // r10size_t v13; // r0signed int input_len; // r9size_t v15; // r0const char *v16; // r12int v17; // r3int v18; // t1int v19; // ST0C_4const char *v20; // ST08_4char *v21; // r2signed int v22; // r3char v23; // r1int v24; // r0signed int v25; // r3const char *v26; // r2int v27; // r3char v28; // r0char *v29; // r2char v30; // r1int v31; // r2char *v32; // r3char v33; // t1signed int i; // r3const char *v35; // r6signed int v36; // r9int v37; // t1char *v38; // r6int *v39; // r3int v40; // r0int v41; // r1__pid_t v43; // [sp0h] [bp-2F0h]int v44; // [sp0h] [bp-2F0h]char v45; // [sp18h] [bp-2D8h]char v46; // [sp1Ah] [bp-2D6h]int v47; // [sp1Ch] [bp-2D4h]__int16 v48; // [sp20h] [bp-2D0h]char v49; // [sp22h] [bp-2CEh]char v50; // [sp24h] [bp-2CCh]char v51[128]; // [sp44h] [bp-2ACh]char v52[512]; // [spC4h] [bp-22Ch]input (const char *)((int (*)(void))(*a1)-GetStringUTFChars)();// 读inputv2 getppid();v3 0;v43 v2;dov52[v3] 0;while ( v3 ! 64 );v4 0;dov51[v4] 0;while ( v4 ! 32 );v5 v50;v6 dword_2C6F;do{v7 *v6;v6 2;v8 *(v6 - 1);*(_DWORD *)v5 v7;*((_DWORD *)v5 1) v8;v9 v5 8;v5 8;}while ( v6 ! (int *)unk_2C7F );*v9 *(_BYTE *)v6;sub_1064(v50, 17, 65); // /proc/%d/cmdline v47 0x9021D19;v48 0xD13;v49 0x69;sub_1064(v47, 7, 99); // zygote v10 getppid();snprintf(v51, 32u, v50, v10, v43);v11 open(v51, 0);read(v11, v52, 64u);sub_107E(v52); // sub_107E函数大写转小写close(v11);if ( !strstr(v52, (const char *)v47) )exit(-1);input_ input;v13 strlen(input);BYTE2(v47) 0;v52[0] 0;input_len v13;v15 strlen(input);v16 (const char *)unk_2CF7; // %xv17 v15;while ( input_ - input v17 ){v18 *(unsigned __int8 *)input_;v19 v17;v20 v16;sprintf((char *)v47, v16, v18); // %x输入的字符转成十六进制不会填充2位strcat(v52, (const char *)v47);v17 v19;v16 v20;}v21 (char *)input;v22 0;while ( v22 input_len ) // input[i]^i{v23 *v21 ^ v22;*v21 v23;}v24 sub_10A4(); // tracerpid 反调试if ( v24 ){v26 input;v27 0;v47 v24 - v44 0x1010101;do // input[i]1,0i3{v28 *((_BYTE *)v47 v27);*v26 v28;}while ( v27 ! 4 );}if ( input_len 7 ) // input的前7个字节按顺序放到最后的7个位置其余的依次向前移动结果放在v51{v25 7;do{v29 v51[v25];v30 input[v25];*(v29 - 7) v30;}while ( v25 ! input_len );v31 (int)(input - 1);v32 v51[input_len - 8];do{v33 *(_BYTE *)(v31 1);(v32)[1] v33;}while ( (const char *)v31 ! input 6 );v51[input_len] 0;}for ( i 0; i input_len; i ) // 变换位置后的input与byte_4004异或再放回inputinput[i] v51[i] ^ byte_4004[i];v52[0] 0;v46 0;v35 input;v36 strlen(input);while ( v35 - input v36 ){v37 *(unsigned __int8 *)v35;sprintf(v45, (const char *)unk_2CF7, v37);// %xstrcat(v52, v45); // input字符转成十六进制数放到v52}v38 v50;v39 dword_2C87;do{v40 *v39;v39 2;v41 *(v39 - 1);*(_DWORD *)v38 v40;*((_DWORD *)v38 1) v41;v38 8;}while ( v39 ! dword_2CA7 );sub_1064(v50, 32, 57); // v50ddedd4ea2e7bef168491a6cae2bc660\x00return strcmp(v50, v52) 0; // v50和v52比较
}需要注意的地方有两点 1、在解最后要去比较的v50时只能得到31个可见字符ddedd4ea2e7bef168491a6cae2bc660原因是使用%x做参数转成十六进制数时某个字节的1个0被忽略但是并不知道是哪个字节转十六进制时忽略了0因此需要爆破0的位置 2、byte_4004数组在ida中直接可见16个字节 其中dword_4007在程序运行时被赋了新值交叉引用过去就能看到 写逆运算脚本打印的字符串中有可读意义的即为flag
#coding:utf-8
from Crypto.Util.number import long_to_bytes
byte_4004[0x85, 0x8B, 0xEC, 0x83, 0xEC, 0x14, 0x83, 0x8D, 0x0C, 0x01,0x75, 0x5F, 0xC6, 0x45, 0xF3, 0x50]
byte_4004[3]0x83
byte_4004[4]0x6c
byte_4004[5]0x9c
byte_4004[6]0x83v50ddedd4ea2e7bef168491a6cae2bc660#长度为31
flags[]
for i in range(32): #爆破被忽略的1个0的位置pv50[:i]0v50[i:]flags.append(long_to_bytes(int(0xp,16)))
for s in flags:flag[]for i in range(16):pord(s[i])^byte_4004[i]flag.append(p)flagflag[-7:]flag[:-7]for i in range(4):flag[i]-1for i in range(16):flag[i]^iprint(.join(chr(i) for i in flag))
#Go0dj06_n1cew0rkDebugMe
elf文件无壳ida分析 main函数主要逻辑为 命令行输入passwordsub_A30函数中有个j_fork不太明白什么作用 往下走输入和下标循环异或进入sub_D90-sub_C14验证输入第二个参数为0 继续向下输入和数字1循环异或进入sub_C14验证输入第二个参数为7
int __cdecl main(int argc, const char **argv, const char **envp)
{int v3; // r4size_t i; // r4int v5; // r5int v6; // r0int v7; // r0int v8; // r7size_t j; // r4const char *v10; // r0char *input_; // [sp4h] [bp-A4h]void (__noreturn *v13)(); // [sp10h] [bp-98h]int v14; // [sp18h] [bp-90h]char v15; // [sp20h] [bp-88h]char v16; // [sp21h] [bp-87h]char v17; // [sp22h] [bp-86h]char v18; // [sp24h] [bp-84h]char v19[20]; // [sp38h] [bp-70h]char v20[64]; // [sp4Ch] [bp-5Ch]if ( argc ! 2 ){j_puts(Usage:\t program_name password);j_exit(0);}input_ (char *)argv[1];if ( sub_A30(2u, (int)argv) ) // 不太明白作用{for ( i 0; i j_strlen(input_); i )input[i] input_[i] ^ i; // input[i]^i}v3 0;v13 sub_D90; // check input主要是sub_C14(input, 0)的调用v14 0;j_sigaction(7, (int)v13, 0);j_sigaction(11, (int)v13, 0);dov20[v3] 0;while ( v3 ! 64 );v5 0;dov19[v5] 0;while ( v5 ! 32 );j_memcpy(v18, unk_213D, 17u);sub_AE4((int)v18, 17, 65); // /proc/%d/cmdline v15 36;v16 61;v17 83;v6 sub_AE4((int)v15, 3, 87); // sh v7 j_getppid(v6);j_snprintf(v19, 32, v18, v7);v8 j_open(v19, 0);j_read();sub_A0C(v20); // 大写转小写j_close(v8);if ( !j_strstr(v20, v15) ){for ( j 0; j j_strlen(input_); j ) // input[i]^1input[j] input_[j] ^ 1;}if ( !sub_B1C() ) // 反调试__breakpoint(0);if ( sub_C14(input, 7) ) // sub_C14(input, 7) 的调用和上面的的调用比较第二个参数不同v10 you win!\nFlag is your password!;elsev10 The password you input is wrong!;j_puts(v10);return 0;
}进入sub_C14函数重要的逻辑在switch case语句中按照v3的值验证输入的内容LABEL_26的代码是变换v3的值实际上v3 7 * (v3 1) - 11*sub_E14(7 * (v3 1), 11) 把sub_E14函数的代码抠出来编写c程序 两次调用sub_C14函数时第二个参数也就是v3的初始值分别为0和7于是验证顺序分别为 v3初始为00 7 1 3 6 5 9 4 2 v3初始为77 1 3 6 5 9 4 2 当v3为2时sub_C14函数返回1 可以看到v3初始为7时比v3初始为0时前者少验证了1位其他的验证顺序是一致的
int __fastcall sub_C14(_BYTE *a1, int a2)
{_BYTE *input; // r4int v3; // r7int v4; // r3int v5; // r5int v6; // r0int v7; // r0int v8; // r6int result; // r0int v10; // r1char v11; // [sp1Ch] [bp-9Ch]char v12; // [sp28h] [bp-90h]char v13; // [sp38h] [bp-80h]char v14[20]; // [sp48h] [bp-70h]char v15[64]; // [sp5Ch] [bp-5Ch]input a1;v3 a2; // v3a2第二个参数在两次调用中不同0和7while ( 2 ){v4 0;dov15[v4] 0;while ( v4 ! 64 );v5 0;dov14[v5] 0;while ( v5 ! 32 );j_memcpy(v12, unk_2113, 0xFu);sub_BF8((int)v12, 15, 107); // /proc/%d/wchan j_memcpy(v13, unk_2122, 0xFu);sub_BF8((int)v13, 15, 116); // sys_epoll_wait j_memcpy(v11, unk_2131, 0xCu);v6 sub_BF8((int)v11, 12, 114); // ptrace_stop v7 j_getppid(v6);j_snprintf(v14, 32, v12, v7);v8 j_open(v14, 0);j_read();sub_A0C(v15); // 大写转小写j_close(v8);if ( j_strstr(v15, v13) ) // 反调试return -1;result -((unsigned int)j_strstr(v15, v11) 1);if ( result -1 ) // 反调试return result;switch ( v3 ) // 验证input内容{case 0:if ( *input 105 )goto LABEL_26;return 0;case 1:if ( *input ! 101 )return 0;goto LABEL_26;case 3:if ( *input ! 110 )return 0;goto LABEL_26;case 4:if ( *input ! 100 )return 0;goto LABEL_26;case 5:if ( *input ! 97 )return 0;goto LABEL_26;case 6:if ( *input ! 103 )return 0;goto LABEL_26;case 7:if ( *input ! 115 )return 0;goto LABEL_26;case 9:if ( *input 114 ){
LABEL_26:sub_EAC(7 * (v3 1), 11); // 调用sub_EAC函数时第二个参数永不为0相当于直接调用sub_E14函数input;v3 v10; // 实际上v37 * (v3 1) - 11*sub_E14(7 * (v3 1), 11)continue;}return 0;default:return 1;}}
}由于v3初始为0时sub_C14函数验证了8位在调用sub_C14函数前输入的变换是input[i]^i 于是写逆运算脚本即可得到8位小写字母即为flag
#coding:utf-8
#按case 0 7 1 3 6 5 9 4 2 顺序装值
a[105,115,101,110,103,97,114,100]
print(.join(chr(a[i]^i)for i in range(len(a))))
#irgmcdtcFindPass
apk文件jadx-gui打开 在com.example.findpass.MainActivity中GetKey方法的逻辑为 获取输入的fkey已知的ekey做变换fkey和变换后的ekey比较验证输入fkey 按照GetKey方法的逻辑写脚本即可得到flag
ekeyTr43Fla92Ch4n93
ekey_data[ord(ekey[i]) for i in range(len(ekey))]
fopen(D:\\ctfdownloadfiles\\src.jpg,rb)
chaf.read(1024)
f.close()
for i in range(len(ekey)):if ord(cha[ord(ekey[i])])128:tmp2ord(cha[ord(ekey[i])])%10else:tmp2 (-(ord(cha[ord(ekey[i])])0x7f)) % 10if i%21:ekey_data[i]tmp2else:ekey_data[i]-tmp2
print(.join(chr(i) for i in ekey_data))
#Qv49CmZB2Df4jB-