Android Armor
Chapters

This chapter will discuss some protections and showcase how they actually work.

Anti-Patching with checksum verification


__attribute__((constructor))
void detectfrida() {

  char *filePaths[NUM_LIBS];

  parse_proc_maps_to_fetch_path(filePaths);

  for (int i = 0; i < NUM_LIBS; i++) {
    fetch_checksum_of_library(filePaths[i], &elfSectionArr[i]);

  if (filePaths[i] != NULL)
    free(filePaths[i]);
  }

  pthread_t t;
  pthread_create(&t, NULL, (void *) detect_frida_loop, NULL);
}

void detect_frida_loop(void *pargs) {

  struct timespec timereq;
  timereq.tv_sec = 5;
  timereq.tv_nsec = 0;

  while (1) {

    // ...
    detect_frida_memdiskcompare();


    my_nanosleep(&timereq, NULL);

  }
}
(source)

The code above computes checksum of loaded binaries in the APK and creates a thread that it's job is constantly checking if the checksums did not change.
You would also notice the use of my_nanosleep, which is because it uses a system call instead of calling the function, making it harder to be hooked. system calls are direct instructions and hooking them would require traversing the instructions in the binraries and placing custom code that might not guarentee working on all cases.

Anti-Hooking by verifying function header

if we look at the open function before hooking, we would notice it's setup bytes:

sub sp, sp, #0x130
stp x29, x30, [sp, #0xe0]
str x28, [sp, #0xf0]

Before Hook
sub sp, sp, #0x130
br x16
adrp x0, #0x7a6a570000
After Hook
(source)

You can notice the first 3 instructions, which are 12 bytes, have changed.
The new instructions simply jump to frida core handler

Simple Anti-Debugging

bool IsDebuggerPresent() {
    return ptrace(PTRACE_TRACEME, 0, 1, 0) < 0;
}

ptrace is a system call that is used to trace a process, but one process can trace another at a time!
Thus, if it returns -1, it means debugger is attached.

Verify Package name

A common technique is used to distribute mods is by changing package name to make it possible to install it without having to uninstall the original APK, and this can be checked by simply getting package name from application context on onCreate method:

@Override
public void onCreate(Bundle instance) {
    super.onCreate(instance);
    setContentView(R.layout.main);

    PACKAGE_NAME = getApplicationContext().getPackageName();
}

Verify APK Signature

Distributed APKs are modified, although apk signature can be easily spoofed, it does not hurt to be added and could stop some:

Signature[] sig = context.getPackageManager()
    .getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES)
    .signatures;
// verify signatures ...

Chapter Contents

Go to next Chapter: