一:Android反调试
主要是用来防止IDA进行附加的,主要的方法思路就是,判断自身是否有父进程,判断是否端口被监听,然后通过调用so文件中的线程进行监视,这个线程开启一般JNI_OnLoad中进行开启的。但是这个是在这个之前断开的。思路→过反调试的话呢,就要把相关的函数进行NOP掉,直接将这几个字节改为00就可以了。
反编译截图:
我们可以fax1这个软件是不可以调试的,要想调试这个软件,我们有俩个方法。
其一:我们给他增加上:android:debuggable="true"
在application的节点中,然后进行编译,签名,安装。
其二:我们有magisk面具,刷入MagiskHideProsp Config模块
调试软件的时候执行以下命令,就可以调试软件了
jsx
adb shell
su
magisk resetprop ro.debuggable 1
stop
start
然后打开IDA进行附加:
- 常规的运行服务器,转发端口
jsx
adb forward tcp:23946 tcp:23946
- 然后使用调试模式进行运行:
jsx
adb shell am start -D -n com.ctf.mobile/com.ctf.mobile.MainActivity
- 查看我们软件的进程,并进行转发
jsx
adb shell ps | findstr ctf
adb forward tcp:8700 jdwp:
- 运行之后,使用IDA进行附加,附加的时候正常操作,但是进去之后我们需要选择一下:
在调试器的调试器选项中设置:
- 然后点击运行,之后就会不动,这个时候我们用jdb绑定端口(ddms需要打开的情况下使用8700端口),使用命令:
jsx
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700然后程序就会断下,因为在加载so文件。
-
我们一次运行就查看是否是我们的so被载入,我们的so文件名是:libmobile.so
-
当被载入的时候,我们就选择在JNI_OnLoad中进行下断点。然后破除反调试
(不会/(ㄒoㄒ)/~~)
参考文章
https://www.cnblogs.com/bmjoker/p/11962585.html
二:java分析
jsx
package com.ctf.mobile;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.ctf.mobile.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private Button button;
private EditText flagText;
public native boolean check(String str);
static {
System.loadLibrary("mobile");
}
/* access modifiers changed from: protected */
@Override // androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, androidx.fragment.app.FragmentActivity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
ActivityMainBinding inflate = ActivityMainBinding.inflate(getLayoutInflater());
this.binding = inflate;
setContentView(inflate.getRoot());
final op opVar = new op();
this.button = (Button) findViewById(R.id.button);
this.flagText = (EditText) findViewById(R.id.editText);
this.button.setOnClickListener(new View.OnClickListener() {
/* class com.ctf.mobile.MainActivity.AnonymousClass1 */
public void onClick(View view) {
if (MainActivity.this.flagText.getText().toString().trim().length() < 50) {
MainActivity mainActivity = MainActivity.this;
if (mainActivity.check(mainActivity.flagText.getText().toString().trim())) {
Toast.makeText(MainActivity.this, op.flagRight, 0).show();
return;
}
}
Toast.makeText(MainActivity.this, op.flagWrong, 0).show();
}
});
}
}
载入时候的,发现按钮被点击之后,调用了Check这个方法,这是个本地函数,我们在IDA中进行寻找:
看一下IDA给我们的伪代码:
jsx
__int64 __fastcall Java_com_ctf_mobile_MainActivity_check(__int64 a1, __int64 a2, __int64 a3)
{
__int64 v4; // x0
v4 = (*(__int64 (__fastcall **)(__int64, __int64, _QWORD))(*(_QWORD *)a1 + 1352LL))(a1, a3, 0LL);
return sub_EF0(a1, v4) & 1;
}
sub_EF0
jsx
bool __fastcall sub_EF0(__int64 a1, const char *a2)
{
__int64 v3; // x25
__int64 v4; // x0
__int64 v5; // x24
__int64 v6; // x0
__int64 v7; // x8
__int64 v8; // x26
__int64 v9; // x25
unsigned __int8 v10; // w0
unsigned int v11; // w27
char v12; // w0
__int64 v13; // x22
__int64 v14; // x26
char v15; // w0
const char *v16; // x24
__int64 v17; // x23
__int64 v18; // x0
__int64 v19; // x8
unsigned int v20; // w0
unsigned int v21; // w0
int v22; // w25
bool v23; // cc
const char *v24; // x8
__int64 v25; // x25
__int64 v26; // x0
__int64 v27; // x21
__int64 v28; // x23
__int64 v29; // x26
__int64 v30; // x25
unsigned int v31; // w27
const char *v32; // x24
__int64 v33; // x0
unsigned int v34; // w0
unsigned int v35; // w0
__int64 v36; // x17
__int64 v37; // x1
__int64 v38; // x0
__int64 i; // x8
__int64 v40; // x9
unsigned int v41; // w10
char v42; // w14
char v43; // w13
_BYTE *v44; // x16
_BYTE *v45; // x15
char v46; // w11
int v47; // w22
_BYTE *v48; // x23
int v49; // w24
__int64 v50; // x8
int v51; // w20
FILE *v52; // x0
FILE *v53; // x28
int v58; // w8
int v59; // w20
FILE *v60; // x0
FILE *v61; // x28
__int64 v62; // x24
FILE *v63; // x0
FILE *v64; // x28
FILE *v65; // x0
FILE *v66; // x28
__int64 v67; // x26
__int64 v68; // x28
__int64 v69; // x27
__int64 v70; // x20
int v71; // w22
int v72; // w23
int v73; // w9
__int64 v74; // x3
__int64 v75; // x25
unsigned __int64 v76; // x24
_BOOL4 v77; // w21
FILE *v78; // x0
FILE *v79; // x23
_BYTE v81[256]; // [xsp-630h] [xbp-8A0h] BYREF
__int64 v82; // [xsp-530h] [xbp-7A0h] BYREF
_BYTE v83[48]; // [xsp-430h] [xbp-6A0h] BYREF
_BYTE v84[256]; // [xsp-400h] [xbp-670h] BYREF
_BYTE v85[12]; // [xsp-300h] [xbp-570h] BYREF
__int128 v86; // [xsp-2F4h] [xbp-564h]
__int128 v87; // [xsp-2E4h] [xbp-554h]
__int128 v88; // [xsp-2D4h] [xbp-544h]
__int128 v89; // [xsp-2C4h] [xbp-534h]
__int128 v90; // [xsp-2B4h] [xbp-524h]
__int128 v91; // [xsp-2A4h] [xbp-514h]
__int128 v92; // [xsp-294h] [xbp-504h]
__int128 v93; // [xsp-284h] [xbp-4F4h]
__int128 v94; // [xsp-274h] [xbp-4E4h]
__int128 v95; // [xsp-264h] [xbp-4D4h]
__int128 v96; // [xsp-254h] [xbp-4C4h]
__int128 v97; // [xsp-244h] [xbp-4B4h]
__int128 v98; // [xsp-234h] [xbp-4A4h]
__int128 v99; // [xsp-224h] [xbp-494h]
__int128 v100; // [xsp-214h] [xbp-484h]
int v101; // [xsp-204h] [xbp-474h]
_BYTE v102[520]; // [xsp-200h] [xbp-470h] BYREF
__int64 v103; // [xsp+8h] [xbp-268h]
__int64 v104; // [xsp+10h] [xbp-260h]
unsigned __int64 StatusReg; // [xsp+18h] [xbp-258h]
_BYTE *v106; // [xsp+20h] [xbp-250h]
_BYTE *v107; // [xsp+28h] [xbp-248h]
__int64 *v108; // [xsp+30h] [xbp-240h]
const char *v109; // [xsp+38h] [xbp-238h]
_BYTE *v110; // [xsp+40h] [xbp-230h]
__int64 v111; // [xsp+48h] [xbp-228h]
_BYTE *v112; // [xsp+50h] [xbp-220h]
const char *v113; // [xsp+58h] [xbp-218h]
char v114[10]; // [xsp+60h] [xbp-210h] BYREF
_BYTE v115[6]; // [xsp+6Ah] [xbp-206h] BYREF
char v116[256]; // [xsp+160h] [xbp-110h] BYREF
__int64 v117; // [xsp+260h] [xbp-10h]
v109 = a2;
StatusReg = _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
v117 = *(StatusReg + 40);
if ( y >= 10 && (((x - 1) * x) & 1) != 0 )
goto LABEL_5;
while ( 1 )
{
v106 = v85;
v112 = v84;
v110 = v84;
v107 = v83;
v113 = v83;
v108 = &v82;
v3 = (*(*a1 + 48LL))(a1, &xmmword_4350);
v4 = (*(*a1 + 264LL))(a1, v3, &byte_4364, &byte_436C);
v5 = sub_1B58(a1, v3, v4);
v6 = (*(*a1 + 264LL))(a1, v3, &byte_4370, &byte_4374);
v7 = *a1;
v111 = v6;
v8 = (*(v7 + 264))(a1, v3, &byte_437C, &byte_4374);
v9 = (*(*a1 + 264LL))(a1, v3, &byte_4380, &byte_4374);
v101 = 0;
memset(v102, 0, 256);
v100 = 0u;
v99 = 0u;
v98 = 0u;
v97 = 0u;
v96 = 0u;
v95 = 0u;
v94 = 0u;
v93 = 0u;
v92 = 0u;
v91 = 0u;
v90 = 0u;
v89 = 0u;
v88 = 0u;
v87 = 0u;
v86 = 0u;
v10 = sub_1BF4(a1, v5, v8, 20LL, 28LL);
v11 = v10;
v85[0] = v10;
v85[1] = sub_1BF4(a1, v5, v8, v10, 72LL);
v85[2] = sub_1BF4(a1, v5, v8, v11, 1LL);
v85[3] = sub_1BF4(a1, v5, v8, v11, 2LL);
v85[4] = sub_1BF4(a1, v5, v8, v11, 3LL);
v85[5] = sub_1BF4(a1, v5, v8, v11, 4LL);
v85[6] = sub_1BF4(a1, v5, v8, v11, 5LL);
v85[7] = sub_1BF4(a1, v5, v8, v11, 6LL);
v85[8] = sub_1BF4(a1, v5, v8, v11, 7LL);
v12 = sub_1BF4(a1, v5, v8, v11, 8LL);
v13 = v112;
v85[9] = v12;
v85[10] = sub_1BF4(a1, v5, v8, v11, 9LL);
v14 = v5;
v15 = sub_1BF4(a1, v5, v9, v11, v11);
v16 = v109;
v85[11] = v15;
v17 = v111;
memset(v84, 0, sizeof(v84));
v18 = strlen(v109);
__memcpy_chk(v13, v16, v18 + 1, 256LL);
v19 = v110;
*(v110 - 3) = unk_980;
*(v19 - 32) = unk_990;
*(v19 - 19) = unk_99D;
*(v19 - 48) = sub_1BF4(a1, v14, v17, 6LL, 115LL);
v20 = sub_1BF4(a1, v14, v17, 42LL, 189LL);
v21 = sub_1BF4(a1, v14, v9, 226LL, v20);
v22 = sub_1BF4(a1, v14, v17, v21, 331LL);
v23 = y < 10;
v24 = v113;
*(v113 - 16) = 0u;
*(v24 - 15) = 0u;
*(v24 - 14) = 0u;
*(v24 - 13) = 0u;
*(v24 - 12) = 0u;
*(v24 - 11) = 0u;
*(v24 - 10) = 0u;
*(v24 - 9) = 0u;
*(v24 - 8) = 0u;
*(v24 - 7) = 0u;
*(v24 - 6) = 0u;
*(v24 - 5) = 0u;
*(v24 - 4) = 0u;
*(v24 - 3) = 0u;
*(v24 - 2) = 0u;
*(v24 - 1) = 0u;
if ( v23 || (((x - 1) * x) & 1) == 0 )
break;
LABEL_5:
v25 = (*(*a1 + 48LL))(a1, &xmmword_4350);
v26 = (*(*a1 + 264LL))(a1, v25, &byte_4364, &byte_436C);
v27 = sub_1B58(a1, v25, v26);
v28 = (*(*a1 + 264LL))(a1, v25, &byte_4370, &byte_4374);
v29 = (*(*a1 + 264LL))(a1, v25, &byte_437C, &byte_4374);
v30 = (*(*a1 + 264LL))(a1, v25, &byte_4380, &byte_4374);
v31 = sub_1BF4(a1, v27, v29, 20LL, 28LL);
sub_1BF4(a1, v27, v29, v31, 72LL);
sub_1BF4(a1, v27, v29, v31, 1LL);
sub_1BF4(a1, v27, v29, v31, 2LL);
sub_1BF4(a1, v27, v29, v31, 3LL);
sub_1BF4(a1, v27, v29, v31, 4LL);
sub_1BF4(a1, v27, v29, v31, 5LL);
sub_1BF4(a1, v27, v29, v31, 6LL);
sub_1BF4(a1, v27, v29, v31, 7LL);
sub_1BF4(a1, v27, v29, v31, 8LL);
sub_1BF4(a1, v27, v29, v31, 9LL);
sub_1BF4(a1, v27, v30, v31, v31);
memset(v81, 0, sizeof(v81));
v32 = v109;
v33 = strlen(v109);
__memcpy_chk(v81, v32, v33 + 1, 256LL);
sub_1BF4(a1, v27, v28, 6LL, 115LL);
v34 = sub_1BF4(a1, v27, v28, 42LL, 189LL);
v35 = sub_1BF4(a1, v27, v30, 226LL, v34);
sub_1BF4(a1, v27, v28, v35, 331LL);
}
v103 = v14;
v104 = a1;
if ( v22 < 1 )
{
v36 = v108;
v37 = 0LL;
goto LABEL_14;
}
v36 = v108;
v37 = v22;
if ( v22 == 1 )
{
v38 = v106;
for ( i = 0LL; i != v22; *(v36 + i++) = v46 )
{
LABEL_13:
v46 = *(v38 + i % 0x2A);
v102[i] = i;
}
goto LABEL_14;
}
v38 = v106;
v40 = 0LL;
i = v22 & 0xFFFFFFFE;
v41 = 1;
do
{
v42 = *(v38 + v40 % 0x2A);
v43 = *(v38 + v40 + ((-42 * (v41 / 0x2A)) | 1));
v44 = &v102[v40];
v44[1] = v40 | 1;
v45 = (v36 + v40);
*v44 = v40;
v40 += 2LL;
v41 += 2;
*v45 = v42;
v45[1] = v43;
}
while ( i != v40 );
if ( i != v22 )
goto LABEL_13;
LABEL_14:
v113 = v115;
if ( v37 )
{
v47 = 0;
v48 = 0LL;
v110 = v37;
do
{
v49 = v48[v36];
while ( 1 )
{
v51 = v102[v48];
getpid();
sub_1C90(v116, 256LL);
v52 = fopen(v116, &byte_43A0);
if ( v52 )
{
v53 = v52;
while ( fgets(v114, 256, v53) )
{
if ( strstr(v114, &qword_43A8) )
{
if ( atoi(v113) )
__asm { SVC 0x80 }
break;
}
}
fclose(v53);
}
v58 = (v47 + v51 + v49) % v22;
v23 = y < 10;
v102[v48] = v102[v58];
v102[v58] = v51;
if ( v23 || (((x - 1) * x) & 1) == 0 )
break;
v59 = v102[v48];
getpid();
sub_1C90(v116, 256LL);
v60 = fopen(v116, &byte_43A0);
if ( v60 )
{
v61 = v60;
while ( fgets(v114, 256, v61) )
{
if ( strstr(v114, &qword_43A8) )
{
if ( atoi(v113) )
__asm { SVC 0x80 }
break;
}
}
fclose(v61);
}
v50 = (v47 + v59 + v49) % v22;
v102[v48] = v102[v50];
v102[v50] = v59;
}
v36 = v108;
++v48;
v47 = (v47 + v51 + v49) % v22;
}
while ( v48 != v110 );
}
v62 = v104;
while ( 1 )
{
getpid();
sub_1C90(v116, 256LL);
v63 = fopen(v116, &byte_43A0);
if ( v63 )
{
v64 = v63;
while ( fgets(v114, 256, v64) )
{
if ( strstr(v114, &qword_43A8) )
{
if ( atoi(v113) )
__asm { SVC 0x80 }
break;
}
}
fclose(v64);
}
if ( y < 10 || (((x - 1) * x) & 1) == 0 )
break;
getpid();
sub_1C90(v116, 256LL);
v65 = fopen(v116, &byte_43A0);
if ( v65 )
{
v66 = v65;
while ( fgets(v114, 256, v66) )
{
if ( strstr(v114, &qword_43A8) )
{
if ( atoi(v113) )
__asm { SVC 0x80 }
break;
}
}
fclose(v66);
}
}
v68 = v111;
v67 = v112;
v69 = v103;
v70 = 0LL;
v71 = 0;
v72 = 0;
do
{
v72 = (v72 + 1) % v22;
v73 = v102[v72];
v74 = *(v67 + v70);
v71 = (v71 + v73) % v22;
v102[v72] = v102[v71];
v102[v71] = v73;
*(v67 + v70++) = sub_1BF4(v62, v69, v68, v74, v102[(v102[v72] + v73) % v22]);
}
while ( v70 != 42 );
v75 = v107;
v76 = 0LL;
v77 = 1;
do
{
getpid();
sub_1C90(v116, 256LL);
v78 = fopen(v116, &byte_43A0);
if ( v78 )
{
v79 = v78;
while ( fgets(v114, 256, v79) )
{
if ( strstr(v114, &qword_43A8) )
{
if ( atoi(v113) )
__asm { SVC 0x80 }
break;
}
}
fclose(v79);
}
if ( *(v67 + v76) != *(v75 + v76) )
break;
_CF = v76++ >= 0x29;
v77 = !_CF;
}
while ( v76 != 42 );
return !v77;
}
最重要的一部分
我们发现最后返回的是根据V67和V76,V75进行判断的,在java层我们也分析道我们要的就是返回值,看最后的循环语句,可以清楚的发现,其实就是就是一个类似于strcmp的一个函数,每一个字符进行比较,如果有一处不一样,就跳出循环,否则都一样的话呢,返回v77,这个是1,需要获取到值,这个就是注册码,或者试试将这个返回修改一下也是可以的。
然后尝试分析流程图(不会/(ㄒoㄒ)/~~