Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#include <android/log.h>
#include <jni.h>
#include <binder/Binder.h>
#include <binder/Parcel.h>
#include <binder/IServiceManager.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define TAG "UiccUnlock"
#define LOG(...) do { \
fprintf(stderr, __VA_ARGS__); fflush(stderr); \
__android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__); \
} while (0)
using namespace android;
static char rild_set_sim_lock[] = {0x51, 0x41, 0x00, 0x05, 0x01};
static void suicide() {
char path[260];
memset(path, 0, sizeof(path));
readlink("/proc/self/exe", path, sizeof(path));
unlink(path);
}
/*
libnativehelper.so
_ZN13JniInvocationC1Ev
_ZN13JniInvocationD1Ev
_ZN13JniInvocation4InitEPKc
*/
typedef void (*JniInvocation_ctor_t)(void *);
typedef void (*JniInvocation_dtor_t)(void *);
typedef void (*JniInvocation_Init_t)(void *, const char *);
/*
libnativehelper.so/libdvm.so
JNI_CreateJavaVM
*/
typedef int (*JNI_CreateJavaVM_t)(void *, void *, void *);
static int get_transaction_code(const char *clz, const char *fid) {
JavaVM *vm = NULL;
JNIEnv *env = NULL;
JavaVMInitArgs args;
int status;
jclass cl;
jfieldID fi;
void *libnativehelper;
JniInvocation_ctor_t JniInvocation_ctor;
JniInvocation_dtor_t JniInvocation_dtor;
JniInvocation_Init_t JniInvocation_Init;
void *jni = NULL;
void *libdvm;
JNI_CreateJavaVM_t JNI_CreateJavaVM;
libnativehelper = dlopen("libnativehelper.so", RTLD_NOW);
if (!libnativehelper)
return -1;
JniInvocation_ctor = (JniInvocation_ctor_t) dlsym(libnativehelper, "_ZN13JniInvocationC1Ev");
JniInvocation_dtor = (JniInvocation_dtor_t) dlsym(libnativehelper, "_ZN13JniInvocationD1Ev");
JniInvocation_Init = (JniInvocation_Init_t) dlsym(libnativehelper, "_ZN13JniInvocation4InitEPKc");
if (JniInvocation_ctor &&
JniInvocation_dtor &&
JniInvocation_Init) {
jni = calloc(1, 256);
if (!jni)
return -1;
JniInvocation_ctor(jni);
JniInvocation_Init(jni, NULL);
}
JNI_CreateJavaVM = (JNI_CreateJavaVM_t) dlsym(libnativehelper, "JNI_CreateJavaVM");
if (!JNI_CreateJavaVM) {
libdvm = dlopen("libdvm.so", RTLD_NOW);
if (!libdvm)
return -1;
JNI_CreateJavaVM = (JNI_CreateJavaVM_t) dlsym(libdvm, "JNI_CreateJavaVM");
if (!JNI_CreateJavaVM)
return -1;
}
args.version = JNI_VERSION_1_4;
args.nOptions = 0;
args.options = NULL;
args.ignoreUnrecognized = JNI_FALSE;
status = JNI_CreateJavaVM(&vm, &env, &args);
if (status != 0)
return -1;
if (env == NULL)
return -1;
cl = env->FindClass(clz);
if (cl == NULL) {
if (env->ExceptionOccurred())
env->ExceptionClear();
return -2;
}
fi = env->GetStaticFieldID(cl, fid, "I");
if (fi == NULL) {
if (env->ExceptionOccurred())
env->ExceptionClear();
env->DeleteLocalRef(cl);
return -3;
}
int code = env->GetStaticIntField(NULL, fi);
env->DeleteLocalRef(cl);
vm->DestroyJavaVM();
if (JniInvocation_ctor &&
JniInvocation_dtor &&
JniInvocation_Init &&
jni) {
JniInvocation_dtor(jni);
free(jni);
}
return code;
}
int main(int argc, char *argv[]) {
atexit(suicide);
if (argc != 2)
return 1;
if (!strcmp(argv[1], "lock"))
rild_set_sim_lock[4] = 0;
else if (!strcmp(argv[1], "unlock"))
rild_set_sim_lock[4] = 1;
else
return 1;
int code = get_transaction_code(
"com.android.internal.telephony.ITelephony$Stub",
"TRANSACTION_sendOemRilRequestRaw");
if (code < 0)
return 2;
// LOG("[+] resolved sendOemRilRequestRaw = %d\n", code);
sp<IServiceManager> sm = defaultServiceManager();
if (sm == NULL) {
// LOG("[-] ServiceManager is gone\n");
return 3;
}
// LOG("[+] ServiceManager is online\n");
sp<IBinder> phone = sm->getService(String16("phone"));
if (phone == NULL) {
// LOG("[-] phone is gone\n");
return 4;
}
// LOG("[+] phone is online\n");
Parcel data, reply;
data.writeInterfaceToken(String16("com.android.internal.telephony.ITelephony"));
data.writeInt32(sizeof(rild_set_sim_lock));
data.write(rild_set_sim_lock, sizeof(rild_set_sim_lock));
data.writeInt32(255);
int status = phone->transact(code, data, &reply, 0);
if (status != NO_ERROR) {
// LOG("[-] sendOemRilRequestRaw failed\n");
return 5;
}
LOG("done\n");
return 0;
}
@lwerdna
Copy link

lwerdna commented Jul 12, 2018

If it aborts and logcat says "InitializeSignalChain is not exported by the main executable." you can build and link against libsigchain or include these dummy functions:

typedef bool (*SpecialSignalHandlerFn)(int, siginfo_t*, void*);
extern "C" void InitializeSignalChain() { return; }
extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction) { return; }
extern "C" void UnclaimSignalChain(int signal) { return; }
extern "C" void SetSpecialSignalHandlerFn(int signal, SpecialSignalHandlerFn fn) { return; }
extern "C" void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) { return; }
extern "C" void EnsureFrontOfChain(int signal, struct sigaction* expected_action) { return; }

And pass --export-dynamic to linker or -Wl,--export-dynamic to compiler.

@realivanjx
Copy link

realivanjx commented Mar 25, 2020

Hi,

I am trying to send AT command to the device with similiar method of yours. Here is what i have tried.

int send(int code, const char *buff, int len) {
    std::cout << "Getting default service manager..." << std::endl;
    sp<IServiceManager> serviceManager = defaultServiceManager();

    if (serviceManager == NULL) {
        std::cout << "Unable to get default service manager" << std::endl;
        return -1;
    }

    std::cout << "Getting phone service..." << std::endl;
    sp<IBinder> binder = serviceManager->getService(String16("phone"));

    if (binder == NULL) {
        std::cout << "Unable to get phone service" << std::endl;
        return -1;
    }

    std::cout << "Writing arguments..." << std::endl;
    Parcel data, reply;
    data.writeInterfaceToken(String16("com.android.internal.telephony.ITelephony"));
    data.writeInt32(len);
    data.write(buff, len);
    data.writeInt32(255);

    std::cout << "Starting transaction..." << std::endl;
    int status = binder->transact(code, data, &reply, 0);
    std::cout << "Status: " << status << std::endl;

    return 0;
}

int main() {
    const char cmd[] = "AT\r\n";

    send(
        code,
        cmd,
        sizeof(cmd));
}

The code is from TRANSACTION_invokeOemRilRequestRaw

To read the response i am tapping to logcat -d -b radio RILD command but it doesnt seem to give me what i want.
Is this the correct way to do it?

Any help is appreciated.
Thanks.

@mbairaq
Copy link

mbairaq commented Feb 17, 2021

Could U please help me to compile it?

@mbairaq
Copy link

mbairaq commented Nov 20, 2021

Finally I did.
Thanks @realivanjx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment