Description: Captain Hook has applied for a position in Squid Game 2022, but in order to take part into the game, he got asked to bypass the login screen of this app. Help him bypass it and he wont have the crocodile eat your hand.

Install the APK file with ADB
adb install -r Captain_Hook.apk
We can see a login activity. Which have username
and password
field with a login button.
Let’s inspect the source code with jadx.
Looking in AndroidManifest.xml
file, the package name is com.example.captain_hook
.
And we have two activities:
MainActivity
Game
We have the java code from MainActivity
class:
public class MainActivity extends ActivityC0491h {
/* renamed from: com.example.captain_hook.MainActivity$a */
public class ViewOnClickListenerC0367a implements View.OnClickListener {
/* renamed from: b */
public final /* synthetic */ EditText f2300b;
/* renamed from: c */
public final /* synthetic */ EditText f2301c;
public ViewOnClickListenerC0367a(EditText editText, EditText editText2) {
this.f2300b = editText;
this.f2301c = editText2;
}
@Override // android.view.View.OnClickListener
public void onClick(View view) {
if (!this.f2300b.getText().toString().equals("mitroglou") || !this.f2301c.getText().toString().equals(MainActivity.this.stringFromJNI())) {
Toast.makeText(MainActivity.this, "Wrong username or password!", 1).show();
return;
}
Intent intent = new Intent(MainActivity.this, (Class>) Game.class);
intent.putExtra("key", MainActivity.this.stringFromJNI());
MainActivity.this.startActivity(intent);
}
}
static {
System.loadLibrary("captain_hook");
}
@Override // androidx.fragment.app.ActivityC0220q, androidx.activity.ComponentActivity, p066w.ActivityC0803f, android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
View inflate = getLayoutInflater().inflate(R.layout.activity_main, (ViewGroup) null, false);
int i2 = R.id.button;
if (((Button) C0359b.m1359c(inflate, R.id.button)) != null) {
if (((EditText) C0359b.m1359c(inflate, R.id.pass)) == null) {
i2 = R.id.pass;
} else if (((TextView) C0359b.m1359c(inflate, R.id.sample_text)) == null) {
i2 = R.id.sample_text;
} else if (((TextView) C0359b.m1359c(inflate, R.id.show)) == null) {
i2 = R.id.show;
} else if (((TextView) C0359b.m1359c(inflate, R.id.textView3)) == null) {
i2 = R.id.textView3;
} else {
if (((EditText) C0359b.m1359c(inflate, R.id.uname)) != null) {
setContentView((ConstraintLayout) inflate);
EditText editText = (EditText) findViewById(R.id.uname);
EditText editText2 = (EditText) findViewById(R.id.pass);
((Button) findViewById(R.id.button)).setOnClickListener(new ViewOnClickListenerC0367a(editText, editText2));
return;
}
i2 = R.id.uname;
}
}
throw new NullPointerException("Missing required view with ID: ".concat(inflate.getResources().getResourceName(i2)));
}
public native String stringFromJNI();
}
In this simple java code we can find some functions and methods.
For example, we notice that a native lib are loaded that returns a String.
Here’s the if condition when the button is pressed In this simple java code we can find some functions and methods.
For example, we notice that a native lib are loaded that returns a String.
This will trigger the Game method code. And a new textView
will appear with the flag if we press the button:
if (!this.f2300b.getText().toString().equals("mitroglou") || !this.f2301c.getText().toString().equals(MainActivity.this.stringFromJNI())) {
Toast.makeText(MainActivity.this, "Wrong username or password!", 1).show();
return;
}
If both the username and the password match, an Intent
is created:
Intent intent = new Intent(MainActivity.this, (Class>) Game.class);
intent.putExtra("key", MainActivity.this.stringFromJNI());
MainActivity.this.startActivity(intent);
This launches the Game
activity, which likely displays the flag:
public class Game extends ActivityC0491h {
@Override // androidx.fragment.app.ActivityC0220q, androidx.activity.ComponentActivity, p066w.ActivityC0803f, android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_game);
String stringExtra = getIntent().getStringExtra("key");
if (stringExtra.isEmpty()) {
return;
}
((TextView) findViewById(R.id.textView3)).setText(stringExtra);
}
}
The code is obfuscated, so to hook into the internal logic, we first enumerate the internal classes:
Java.perform(() => {
Java.enumerateLoadedClasses({
onMatch(name) {
if (name.includes("MainActivity") && name.includes("$")) {
console.log("[*] Internal class:", name);
}
},
onComplete() {
console.log("[*] Let's hook the internal class :)");
}
});
});
Run the frida command and we notice the class:
frida -U "Captain_Hook" -l hookClass.js
Output:
[*] Internal class: com.example.captain_hook.MainActivity$a
[*] Let's hook the internal class :)
[Redmi Note 8::Captain_Hook ]->
We got the class com.example.captain_hook.MainActivity$a
.
Now we can craft this JavaScript code that create a new instance and intercept the onClick()
method:
Java.perform(() => {
const MainActivity = Java.use("com.example.captain_hook.MainActivity");
const ClickHandler = Java.use("com.example.captain_hook.MainActivity$a");
ClickHandler.onClick.implementation = function(view) {
// execute when login button is clicked
this.onClick(view);
try {
// create a new instance of MainActivity
const instance = MainActivity.$new();
const flag = instance.stringFromJNI();
console.log("[+] FLAG: " + flag);
} catch (err) {
console.log("[-] Error due stringFromJNI: " + err);
}
};
});
Run the frida script and then, press the LOGIN button.
Output:
[Redmi Note 8::Captain_Hook ]-> [+] FLAG: UNIWA{Y0u_Ar3_my_C4pt@in}
Okey, we got the flag.
Flag: UNIWA{Y0u_Ar3_my_C4pt@in}
However, this approach doesn’t trigger the Game
activity, since we’re calling the native method from a new instance.
To replicate the full behavior of the original logic (including launching the Game activity), we can modify the hook as follows:
Java.perform(() => {
const MainActivity = Java.use("com.example.captain_hook.MainActivity");
const Game = Java.use("com.example.captain_hook.Game");
const Intent = Java.use("android.content.Intent");
const ClickHandler = Java.use("com.example.captain_hook.MainActivity$a");
ClickHandler.onClick.implementation = function(view) {
// execute onClick method
this.onClick(view);
try {
const activity = Java.cast(view.getContext(), MainActivity);
const flag = activity.stringFromJNI();
// send the Intent to Game
const intent = Intent.$new(activity, Game.class);
intent.putExtra("key", flag);
activity.startActivity(intent);
console.log("[+] Game launched: " + flag);
} catch (err) {
console.log("[-] Error launching Game: " + err);
}
};
});
This will trigger the Game method code. And a new textView
will appear with the flag if we press the button!

I hope you found it useful (:
Leave a Reply