两道简单的CTF
本帖最后由 Anonymous、 于 2018-11-12 20:55 编辑一、说明
两个CTF是一个群友前两天给我的,比较简单,自己比较菜,有什么不对的地方,还请各位师傅指点.
二、第一个CTF
这一题比较简单,先打开app看下
java层代码很简单,就是调用native层的一个校验函数
protected void onCreate(Bundle arg2) {
super.onCreate(arg2);
this.setContentView(0x7F09001C);
this.findViewById(0x7F070022).setOnClickListener(new View$OnClickListener() {
public void onClick(View arg3) {
if(check.checkflag(MainActivity.this.findViewById(0x7F070036).getText().toString())) {
Toast.makeText(MainActivity.this, "you are right~!", 1).show();
}
else {
Toast.makeText(MainActivity.this, "wrong!", 1).show();
}
}
});
}
public class check {
static {
System.loadLibrary("checkso");
}
public check() {
super();
}
public static native boolean checkflag(String arg0) {
}
}
看下 native层函数
.text:00000E54 PUSH {R4,R6,R7,LR}
.text:00000E56 ADD R7, SP, #8
.text:00000E58 MOV R1, R2
.text:00000E5A LDR R2,
.text:00000E5C LDR.W R3,
.text:00000E60 MOVS R2, #0
.text:00000E62 BLX R3 ; 获取输入的值
.text:00000E64 MOV R4, R0; R4 = R0 = input
.text:00000E66 BL sub_E08 ; 未传入参数,无返回值,暂时不分析
.text:00000E6A LDR R0, =(off_6004 - 0xE70)
.text:00000E6C ADD R0, PC; off_6004
.text:00000E6E LDR R1, ; "c2RuaXNjc2RuaXNjYWJjZA=="
.text:00000E70 MOV R0, R4; s1
.text:00000E72 BLX strcmp; 比较输入的值和R1 R1 = "c2RuaXNjc2RuaXNjYWJjZA=="
.text:00000E76 CLZ.W R0, R0
.text:00000E7A LSRS R0, R0, #5
.text:00000E7C POP {R4,R6,R7,PC}
这么简单????那么我们输入c2RuaXNjc2RuaXNjYWJjZA==,试下,wrong~~~~~~~~~,要you are right~!才算正确~~~进去sub_E08,这个函数看下
.text:00000E08 ; Java_com_example_p7xxtmx_1g_fakefunc_check_checkflag+12↓p
.text:00000E08 ; __unwind {
.text:00000E08 PUSH {R4,R6,R7,LR}
.text:00000E0A ADD R7, SP, #8
.text:00000E0C LDR R0, =(off_6004 - 0xE12)
.text:00000E0E ADD R0, PC; off_6004
.text:00000E10 LDR R4, ; "c2RuaXNjc2RuaXNjYWJjZA=="
.text:00000E12 MOV R0, R4; s
.text:00000E14 BLX strlen; 去c2RuaXNjc2RuaXNjYWJjZA==的长度
.text:00000E18 MOV R1, R0
.text:00000E1A MOV R0, R4
.text:00000E1C POP.W {R4,R6,R7,LR}
.text:00000E20 B.W sub_16D8 ; 将c2RuaXNjc2RuaXNjYWJjZA==和其长度传入
再看sub_16d8这个函数
// write access to const memory has been detected, the output may be wrong!
int __fastcall sub_16D8(int a1, int a2)
{
int v2; // r4
int v3; // r5
int v4; // r6
int v5; // r7
int v6; // r8
int v7; // r9
int v8; // r10
int v9; // r11
int v10; // r10
int v11; // r6
int v12; // r5
void *v13; // r9
int v14; // r11
int v15; // r11
unsigned int v16; // r10
bool v17; // zf
int v18; // r0
unsigned int i; // r1
int j; // r1
unsigned int k; // r1
int l; // r0
unsigned int m; // r2
size_t v24; // r6
int n; // r2
int result; // r0
int v27; //
int v28; //
size_t v29; //
_BYTE v30; //
char v31; //
char v32; //
char v33; //
char v34; //
int v35; //
int v36; //
int v37; //
int v38; //
int v39; //
int v40; //
int v41; //
int v42; //
int v43; //
v40 = v2;
v41 = v3;
v42 = v4;
v43 = v5;
v36 = v6;
v37 = v7;
v38 = v8;
v39 = v9;
v10 = a1;
v11 = a2;
v12 = 0;
v13 = malloc(0);
if ( v13 )
{
v14 = 0;
v27 = v10;
v29 = 0;
LABEL_3:
v28 = v14;
v15 = v14 + v10;
v16 = 0;
while ( 1 )
{
v17 = v11 == v16;
if ( v11 != v16 )
{
v12 = *(v15 + v16);
v17 = v12 == 61;
}
if ( v17 || !isalnum(v12) && (v12 | 4) != 47 )
break;
v30 = v12;
if ( v16 == 4 )
{
v11 -= 4;
v18 = 0;
v14 = v28 + 4;
while ( v18 != 4 )
{
for ( i = 0; i <= 0x3F; ++i )
{
if ( v30 == byte_4455 )
{
v30 = i;
break;
}
}
++v18;
}
v34 = v31 + (v30 << 6);
v32 = (v30 >> 4) & 3 | 4 * v30;
v12 = v29;
v33 = (v30 >> 2) & 0xF | 16 * v30;
v13 = realloc(v13, v29 + 3);
for ( j = 0; j != 3; ++j )
*(v13 + v29 + j) = *(&v32 + j);
v29 += 3;
v10 = v27;
goto LABEL_3;
}
}
if ( v16 )
{
for ( k = v16; k < 4; ++k )
v30 = 0;
for ( l = 0; l != 4; ++l )
{
for ( m = 0; m <= 0x3F; ++m )
{
if ( v30 == byte_4455 )
{
v30 = m;
break;
}
}
}
v34 = v31 + (v30 << 6);
v32 = (v30 >> 4) & 3 | 4 * v30;
v33 = (v30 >> 2) & 0xF | 16 * v30;
v24 = v29 + v16 - 1;
v13 = realloc(v13, v24);
for ( n = 0; v16 - 1 != n; ++n )
*(v13 + v29 + n) = *(&v32 + n);
}
else
{
v24 = v29;
}
v12 = realloc(v13, v24 + 1);
*(v12 + v24) = 0;
}
result = _stack_chk_guard - v35;
if ( _stack_chk_guard == v35 )
result = v12;
return result;
}
是不是很长 ,是不是很怕~,这个函数只是进行Base64解密,结果sdniscsdniscabcd,但是这个结果,上层函数并没有使用,所以分析了半天,这个函数居然没用~~~~~
这个时候我们就要想下是不是JNI_OnLoad或者.init_array是否被做了手脚了,先看JNI_OnLoad,并没有什么可疑的地方
.text:00000E84 ; signed int __fastcall JNI_OnLoad(_JNIEnv *a1, int a2, int a3, int a4)
.text:00000E84 EXPORT JNI_OnLoad
.text:00000E84 JNI_OnLoad ; DATA XREF: LOAD:00000220↑o
.text:00000E84
.text:00000E84 var_10 = -0x10
.text:00000E84 var_C = -0xC
.text:00000E84
.text:00000E84 ; __unwind {
.text:00000E84 PUSH {R2-R4,R6,R7,LR}
.text:00000E86 ADD R7, SP, #0x10
.text:00000E88 LDR R1, =(__stack_chk_guard_ptr - 0xE90)
.text:00000E8A LDR R2, =0x10006
.text:00000E8C ADD R1, PC; __stack_chk_guard_ptr
.text:00000E8E LDR R4, ; __stack_chk_guard
.text:00000E90 LDR R1,
.text:00000E92 STR R1,
.text:00000E94 MOVS R1, #0
.text:00000E96 STR R1,
.text:00000E98 LDR R1,
.text:00000E9A LDR R3,
.text:00000E9C MOV R1, SP
.text:00000E9E BLX R3 ; FindClass
.text:00000EA0 MOV R1, R0
.text:00000EA2 MOV.W R0, #0xFFFFFFFF
.text:00000EA6 CMP R1, #0
.text:00000EA8 ITT EQ
.text:00000EAA MOVEQ R0, #6
.text:00000EAC MOVTEQ.W R0, #1
.text:00000EB0 LDR R1,
.text:00000EB2 LDR R2,
.text:00000EB4 SUBS R1, R2, R1
.text:00000EB6 ITT EQ
.text:00000EB8 ADDEQ SP, SP, #8
.text:00000EBA POPEQ {R4,R6,R7,PC}
.text:00000EBC BLX __stack_chk_fail
再看.init_array,调用sub_F20
.text:00000F20 sub_F20 ; DATA XREF: .init_array:00005E00↓o
.text:00000F20 ; __unwind {
.text:00000F20 B.W sub_EC8
.text:00000F20 ; } // starts at F20
再调用sub_EC8
.text:00000EC8 sub_EC8 ; CODE XREF: sub_F20↓j
.text:00000EC8 ; __unwind {
.text:00000EC8 PUSH {R4,R6,R7,LR}
.text:00000ECA ADD R7, SP, #8
.text:00000ECC LDR R0, =(strcmp_ptr - 0xED4)
.text:00000ECE LDR R1, =(sub_E28+1 - 0xED8)
.text:00000ED0 ADD R0, PC; strcmp_ptr
.text:00000ED2 LDR R2, =(dword_6008 - 0xEDC)
.text:00000ED4 ADD R1, PC; sub_E28
.text:00000ED6 LDR R4, ; __imp_strcmp
.text:00000ED8 ADD R2, PC; dword_6008
.text:00000EDA MOV R0, R4
.text:00000EDC BLX j_registerInlineHook ; 将strcmp替换为sub_E28,将dword_6008替换为strcmp
.text:00000EE0 CBZ R0, loc_EE8
.text:00000EE2 MOV.W R0, #0xFFFFFFFF.text:00000EE6 POP {R4,R6,R7,PC}
查看sub_E28
.text:00000E28 PUSH {R4,R6,R7,LR}
.text:00000E2A ADD R7, SP, #8
.text:00000E2C MOV R4, R0; R4 = R0 = input
.text:00000E2E BL sub_E08 ; 之前分析过了,Base64解密,返回值为sdniscsdniscabcd
.text:00000E32 MOV R1, R0; R1 = RO = "sdniscsdniscabcd"
.text:00000E34 MOV R0, R4; R0 = R4 = input
.text:00000E36 BL sub_1388 ; sub_1388(input,"sdniscsdniscabcd")
.text:00000E3A LDR R2, =(dword_6008 - 0xE42)
.text:00000E3C LDR R1, =(aK47Faihmk9Weml - 0xE44)
.text:00000E3E ADD R2, PC; dword_6008
.text:00000E40 ADD R1, PC; "K4/7/faihmk9/WEMlfuFdpgrP86ckd4oQQ/UeAiZdx8="
.text:00000E42 LDR R2,
.text:00000E44 POP.W {R4,R6,R7,LR}
.text:00000E48 BX R2 ; 执行dword_6008,其实是strcmp
所以这个函数的主要意思就是sub_1388(input,"sdniscsdniscabcd"),然后和"K4/7/faihmk9/WEMlfuFdpgrP86ckd4oQQ/UeAiZdx8="比较,我们继续看sub_1388
int __fastcall sub_1388(const char *a1, int a2)
{
int v2; // r9
const char *v3; // r6
signed int v4; // r0
signed int v5; // r4
_BYTE *v6; // r11
signed int j; // r0
const char *v8; // r1
signed int v9; // r8
signed int i; // r1
char *v11; // r2
char v12; // r2
char *v13; // r10
int v14; // r5
int k; // r4
int v16; // r6
v2 = a2;
v3 = a1;
v4 = strlen(a1);
v5 = v4;
if ( v4 > 15 )
{
v9 = (v4 + 16) & 0xFFFFFFF0;
v6 = malloc(v9);
for ( i = 0; ; ++i )
{
if ( i >= v9 )
goto LABEL_16;
if ( i < v5 )
break;
v11 = &unk_4146 + v9 - v5;
if ( v5 & 0xF )
goto LABEL_13;
v12 = 16;
LABEL_14:
v6 = v12;
}
v11 = &v3;
LABEL_13:
v12 = *v11;
goto LABEL_14;
}
v6 = malloc(0x10u);
for ( j = 0; j != 16; ++j )
{
v8 = &unk_4146 + 16 - v5;
if ( j < v5 )
v8 = &v3;
v6 = *v8;
}
v9 = 16;
LABEL_16:
v13 = malloc(v9);
v14 = 0;
for ( k = 0; k < v9 / 16; ++k )
{
sub_F24(&v6, v2, &v13);
v14 += 16;
}
v16 = sub_156C(v13, v9);
free(v6);
free(v13);
return v16;
}
再看sub_F24
int __fastcall sub_F24(int a1, int a2, int a3)
{
int i; // r3
int j; // r1
int v5; // r2
unsigned __int8 *v6; // r3
int v7; // r5
int v8; // r12
int v9; // lr
unsigned __int8 v10; // r1
int v11; // r9
int v12; // r2
int v13; // r0
int k; // r3
_BYTE *v15; // r6
char v16; // r0
char v17; // lr
char v18; // r12
char v19; // r4
char v20; // r3
char v21; // r2
char v22; // r5
char v23; // r4
char v24; // r0
int v25; // r0
int v27; //
_BYTE *v28; //
for ( i = 0; i != 16; ++i )
*(a3 + i) = *(a1 + i);
dword_60BC = a3;
dword_60C0 = a2;
sub_105C();
sub_1524(0);
for ( j = 1; ; j = v27 + 1 )
{
v12 = dword_60BC;
v13 = 0;
v28 = dword_60BC;
while ( v13 != 4 )
{
for ( k = 0; k != 4; ++k )
*(v12 + 4 * k) = RijnDael_AES_LONG_4255[*(v12 + 4 * k)];
++v12;
++v13;
}
v15 = v28;
v16 = v28;
v17 = v28;
v18 = v28;
v19 = v28;
v20 = v28;
v21 = v28;
v28 = v28;
v22 = v28;
v28 = v19;
v23 = v28;
v28 = v16;
v24 = v28;
v28 = v20;
v28 = v21;
v28 = v17;
v28 = v23;
v28 = v22;
v28 = v24;
v15 = v15;
v15 = v15;
v25 = j;
v28 = v18;
if ( j > 9u )
break;
v5 = 0;
v27 = j;
while ( v5 != 4 )
{
v6 = &v28;
v7 = v28;
v8 = v6;
v9 = v6;
v10 = v6;
v11 = v8 ^ v7 ^ v9;
v28 = v7 ^ 2 * (v8 ^ v7) ^ ((v8 ^ v7) >> 7) & 0x1B ^ v11 ^ v10;
v6 = v8 ^ v7 ^ v10 ^ 2 * (v10 ^ v9) ^ ((v10 ^ v9) >> 7) & 0x1B;
v6 = ((v10 ^ v7) >> 7) & 0x1B ^ v11 ^ 2 * (v10 ^ v7);
v6 = v11 ^ v10 ^ v8 ^ 2 * (v9 ^ v8) ^ ((v9 ^ v8) >> 7) & 0x1B;
}
sub_1524(v25);
}
return sub_1524(10);
}
中间很多分支函数,一个个的看,找到关键点AES_LONG_4255,猜测是标准的AES加密,但是那种类型的就不知道,
这时候可疑用一个小工具了,"K4/7/faihmk9/WEMlfuFdpgrP86ckd4oQQ/UeAiZdx8="这是结果,key是"sdniscsdniscabcd"
结果出来了,为flag{fake_func_3nfxvs},其实这题还有其他坑的地方,就是当你用手机打开的时候,你会发现找不到check按钮(上面的是模拟器运行的),
还要自己修改修改布局文件才行,有兴趣的可疑自己试一试,后面会上传apk
三、第二个CTF
先打开app
拉入jeb分析下
public native String getKey(String arg1) {
}
protected void onCreate(Bundle arg4) {
super.onCreate(arg4);
this.setContentView(0x7F09001B);
View v4 = this.findViewById(0x7F070062);
((TextView)v4).setText(this.stringFromJNI());
this.findViewById(0x7F070031).setOnClickListener(new View$OnClickListener() {
public void onClick(View arg5) {
arg5 = MainActivity.this.findViewById(0x7F070062);
String input = MainActivity.this.findViewById(0x7F070003).getText().toString();
if(input.length() == 16) {// 判断是否为16位
input = MainActivity.this.getKey(input);// 调用native方法,从输入的字符串得到key
View v1 = MainActivity.this.findViewById(0x7F070046);
Bitmap v0_1 = MagicImageUtils.readMagicImage(MainActivity.this, "png/encrypt_png.dat", input);// 用key解密图片,然后显示
if(v0_1 != null) {
((TextView)arg5).setText("Congratulations!");
MainActivity.this.showMsgToast("Congratulations!");
((ImageView)v1).setImageBitmap(v0_1);
}
else {
MainActivity.this.showMsgToast("Something wrong!");
}
}
else {
MainActivity.this.showMsgToast("Something wrong!");
}
}
});
View v0 = this.findViewById(0x7F070046);
Bitmap v1 = MagicImageUtils.readImage(((Context)this), "png/bg.png");
if(v1 != null) {
((TextView)v4).setText(" ");
((ImageView)v0).setImageBitmap(v1);
}
else {
this.showMsgToast("Something wrong!");
}
}
看下native层函数,简单分析如下
jstring __fastcall Java_re_sdnisc2018_sdnisc_1apk2_MainActivity_getKey(int a1, int a2, int a3)
{
_JNIEnv *v3; // r5
int input; // r8
int input_len; // r10
int input_key; // r9
signed int i; // r5
char *v8; // r1
int v9; // r0
const char *v10; // r6
char v11; // r0
unsigned int v12; // r0
const char *v13; // r1
jstring v14; // r4
jstring result; // r0
_JNIEnv *v16; //
int v17; //
int v18; //
const char *v19; //
int v20; //
int v21; //
char *v22; //
int v23; //
v3 = a1;
input = a3;
v22 = 0;
v20 = 0;
v21 = 0;
std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::__init(
&v20,
"Welcome_to_sdnisc_2018_By.Zero",
30);
v19 = 0;
v17 = 0;
v18 = 0;
std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::__init(
&v17,
" ",
16);
input_len = (v3->functions->GetStringLength)(v3, input);
v16 = v3;
input_key = (v3->functions->GetStringChars)(v3, input, 0);
for ( i = 0; ; ++i )
{
v12 = sub_75A4D5AC(i, 0x1Eu);
if ( i >= input_len ) // 前面已经分析key的长度只能是16,所以就是循环16次
break;
v8 = v22;
v9 = -30 * v12;
v10 = v19;
if ( !(v20 & 1) )
v8 = &v20 + 1;
v11 = v8;
if ( !(v17 & 1) )
v10 = &v17 + 1;
v10 = v11 ^ *(input_key + 2 * i); // 前面的和key都无关系,只需确认16次v11,里分别是多少
}
v13 = v19;
if ( !(v17 & 1) )
v13 = &v17 + 1;
v14 = v16->functions->NewStringUTF(&v16->functions, v13);
std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::~basic_string(&v17);
std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::~basic_string(&v20);
result = (_stack_chk_guard - v23);
if ( _stack_chk_guard == v23 )
result = v14;
return result;
}
这里v11 ^ *(input_key + 2 * i),是关键部分,但是为什么是input_key + 2 * i呢?动态调试粉线内存存储的是这样的
那就对上了,与我们的key进行亦或,记录16次,v11的值,分别是 0x57,0x65,0x6c,0x63,0x6f,0x6d,0x65,0x5f,0x74,0x6f,0x5f,0x73,0x64,0x6e,0x69,0x73
但是到此为止,我们进行不下去了,16位的key无法穷举,所以只能从java层进行入手了,回到java层
public static native int decrypt(int arg0, char arg1) {
}
public static Bitmap readImage(Context arg6, String arg7) {
Bitmap v6_3;
ArrayList v0 = new ArrayList();
Bitmap v1 = null;
try {
InputStream v6_1 = arg6.getAssets().open(arg7);
while(true) {
int v7 = v6_1.read();
if(v7 <= -1) {
break;
}
((List)v0).add(Byte.valueOf(((byte)v7)));
}
byte[] v6_2 = new byte[((List)v0).size()];
Iterator v7_1 = ((List)v0).iterator();
int v3;
for(v3 = 0; v7_1.hasNext(); ++v3) {
v6_2 = v7_1.next().byteValue();
}
v6_3 = BitmapFactory.decodeByteArray(v6_2, 0, ((List)v0).size());
}
catch(IOException v6) {
goto label_35;
}
try {
System.out.println(v6_3);
return v6_3;
}
catch(IOException v7_2) {
v1 = v6_3;
v6 = v7_2;
}
label_35:
v6.printStackTrace();
return v1;
}
public static Bitmap readMagicImage(Context arg5, String arg6, String arg7) {
Bitmap v5_3;
ArrayList v0 = new ArrayList();
Bitmap v1 = null;
try {
InputStream v5_1 = arg5.getAssets().open(arg6);
int v2;
for(v2 = 0; true; ++v2) {
int v3 = v5_1.read();
if(v3 <= -1) {
break;
}
((List)v0).add(Byte.valueOf(((byte)MagicImageUtils.decrypt(v3, arg7.charAt(v2 % 16)))));
}
byte[] v5_2 = new byte[((List)v0).size()];
Iterator v7 = ((List)v0).iterator();
for(v2 = 0; v7.hasNext(); ++v2) {
v5_2 = v7.next().byteValue();
}
v5_3 = BitmapFactory.decodeByteArray(v5_2, 0, ((List)v0).size());
}
catch(IOException v5) {
goto label_40;
}
try {
System.out.println(v5_3);
return v5_3;
}
catch(IOException v6) {
v1 = v5_3;
v5 = v6;
}
label_40:
v5.printStackTrace();
return v1;
}
readImage,读取正常格式的图片,readMagicImage读取加密的格式,中间的区别只有一个,MagicImageUtils.decrypt(v3, arg7.charAt(v2 % 16))
.text:75A42C30 Java_re_sdnisc2018_sdnisc_1apk2_MagicImageUtils_decrypt
.text:75A42C30 ; __unwind {
.text:75A42C30 SUBS R0, R2, #1
.text:75A42C32 EORS R0, R3
.text:75A42C34 EOR.W R0, R0, #0x61
.text:75A42C38 BX LR
.text:75A42C38 ; } // starts at 75A42C30
很简单,就是进行下亦或解密,由于就多了一步每个字节亦或解密,这时候我们就可以从PNG文件格式入手
三个圈,分别是PNG文件头,chunk长度,chunk标识,三个基本都是不会变得,所以我们用两个头文件前16位进行亦或,拿到key,顺便解密加密的png文件
int png = { 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52 };
int data = { 0xe8,0x36,0x07,0x77,0x2a,0x35,0x3e,0x75,0x35,0x80,0x69,0x42,0x3b,0x6d,0x14,0x6f };
int table = { 0x57,0x65,0x6c,0x63,0x6f,0x6d,0x65,0x5f,0x74,0x6f,0x5f,0x73,0x64,0x6e,0x69,0x73 };
int key;
for (int i = 0; i < 16; i++)
{
printf("%d,", decrypt(data, png));
key = decrypt(data, png);
}
printf("\n");
FILE *p = fopen("c:\\users\\administrator\\desktop\\encrypt_png.dat", "rb");
FILE *fp = fopen("c:\\users\\administrator\\desktop\\dat.png", "wb");
while (!feof(p))
{
for (int i = 0; i < 16; i++)
{
fputc(decrypt(fgetc(p) , key), fp);
}
}
fclose(p);
fclose(fp);
下面是解密的png文件,成功拿到flag
如果这是比赛,到此即可结束了,但是我们出于学习目的,所以继续,拿到安卓端的key才行,前面分析已经拿到了table(就是前面那个16次v11)
所以我们用key再和table亦或下即可
int png = { 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52 };
int data = { 0xe8,0x36,0x07,0x77,0x2a,0x35,0x3e,0x75,0x35,0x80,0x69,0x42,0x3b,0x6d,0x14,0x6f };
int table = { 0x57,0x65,0x6c,0x63,0x6f,0x6d,0x65,0x5f,0x74,0x6f,0x5f,0x73,0x64,0x6e,0x69,0x73 };
int key;
for (int i = 0; i < 16; i++)
{
printf("%d,", decrypt(data, png));
key = decrypt(data, png);
}
printf("\n");
for (int i = 0; i < 16; i++)
{
printf("%c", key ^ table);
}
printf("\n");
成功拿到key,XaE3*2#@!qV^v+_.输入看下结果
贴个完整版的代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int png = { 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52 };
int data = { 0xe8,0x36,0x07,0x77,0x2a,0x35,0x3e,0x75,0x35,0x80,0x69,0x42,0x3b,0x6d,0x14,0x6f };
int table = { 0x57,0x65,0x6c,0x63,0x6f,0x6d,0x65,0x5f,0x74,0x6f,0x5f,0x73,0x64,0x6e,0x69,0x73 };
int key;
int decrypt(int v3, int a4)
{
return (v3 - 1) ^ a4 ^ 0x61;
}
int main(void)
{
for (int i = 0; i < 16; i++)
{
printf("%d,", decrypt(data, png));
key = decrypt(data, png);
}
printf("\n");
for (int i = 0; i < 16; i++)
{
printf("%c", key ^ table);
}
printf("\n");
FILE *p = fopen("c:\\users\\administrator\\desktop\\encrypt_png.dat", "rb");
FILE *fp = fopen("c:\\users\\administrator\\desktop\\dat.png", "wb");
while (!feof(p))
{
for (int i = 0; i < 16; i++)
{
fputc(decrypt(fgetc(p) , key), fp);
}
}
fclose(p);
fclose(fp);
printf("\n");
system("pause");
return 0;
}
第二个也是样本,太大了,分开打包的
很厉害啊,可惜我还不会 膜拜大佬!!!为什么我在反汇编sub_F24后出现的是Byte_4255而不是RijnDael_AES_LONG_4255,大佬是怎么操作的,还是用的什么插件吗?
我也有相同的问题。是安装了findcrypt3么?还是自己看出来之后自己改的名字? 对比我只能做出来找规律的题而言,已经很厉害了 很厉害了!、!! 还不错嘛!! 学到了,多谢了 学习了!! 谢谢分享,学习了~ 下载下来尝试一下 代码看起来挺复杂 很不错,支持楼主一个~