I have been trying to read ARM instruction Opcode of another process but I encounter complications.
Basically I compile my code as a executable using ndk and then I run the executeable using adb shell.
Heres the code I used for trying to achieve my objective:
static void skeleton_daemon()
{
pid_t pid;
/* Fork off the parent process */
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* On success: The child process becomes session leader */
if (setsid() < 0)
exit(EXIT_FAILURE);
/* Catch, ignore and handle signals */
//TODO: Implement a working signal handler */
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
/* Fork off for the second time*/
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* Set new file permissions */
umask(0);
/* Change the working directory to the root directory */
/* or another appropriated directory */
chdir("/");
/* Close all open file descriptors */
int x;
for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
{
close (x);
}
/* Open the log file */
openlog ("ELOS", LOG_PID, LOG_DAEMON);
}
// --------------------------------------------------------------------------
void readMem(int pid, const char* address, int len) {
unsigned long addr = strtoul(address, NULL, 16);
char* mem_dir = (char*) malloc(50);
sprintf(mem_dir, "/proc/%d/mem", pid);
syslog(LOG_NOTICE, "Opening %s and going to address %02X", mem_dir, addr);
int fd_proc_mem = open(mem_dir, O_RDWR);
if (fd_proc_mem == -1) {
syslog(LOG_NOTICE, "Opening failed!");
exit(1);
}
char* buff = (char*) malloc(len);
lseek(fd_proc_mem, addr, SEEK_SET);
read (fd_proc_mem, buff , len);
syslog(LOG_NOTICE, "Data at %02X in process %d is: %02X\n", addr, pid, buff);
free(buff);
free(mem_dir);
}
int main() {
skeleton_daemon();
void* mybuf;
while (1)
{
syslog (LOG_NOTICE, "First daemon starts.");
readMem(6743, "0C133E64", 4); // pid = 6743, address to read = 0C133E64 (shared lib base address + instruction offset), length = 4
break;
}
syslog (LOG_NOTICE, "First daemon terminated.");
closelog();
return EXIT_SUCCESS;
}
On executing via adb the results are as follows:
11-24 15:31:14.263 11166 11166 I ELOS : First daemon starts.
11-24 15:31:14.266 11166 11166 I ELOS : Opening /proc/6743/mem and going to address C133E64
11-24 15:31:14.266 11166 11166 I ELOS : Data at C133E64 in process 6743 is: B6C9A0B8
11-24 15:31:14.267 11166 11166 I ELOS : First daemon terminated.
11-24 15:31:18.122 11176 11176 I ELOS : First daemon starts.
11-24 15:31:18.124 11176 11176 I ELOS : Opening /proc/6743/mem and going to address C133E64
11-24 15:31:18.124 11176 11176 I ELOS : Data at C133E64 in process 6743 is: B6C1A0B8
11-24 15:31:18.125 11176 11176 I ELOS : First daemon terminated.
11-24 15:31:25.689 11194 11194 I ELOS : First daemon starts.
11-24 15:31:25.692 11194 11194 I ELOS : Opening /proc/6743/mem and going to address C133E64
11-24 15:31:25.692 11194 11194 I ELOS : Data at C133E64 in process 6743 is: B6D1A0B8
11-24 15:31:25.693 11194 11194 I ELOS : First daemon terminated.
The result is different in every execution. Why is that so?
Ok so here is how I got it working..
uint32_t reverse_bytes(uint32_t bytes)
{
uint32_t aux = 0;
uint8_t byte;
int i;
for(i = 0; i < 32; i+=8)
{
byte = (bytes >> i) & 0xff;
aux |= byte << (32 - 8 - i);
}
return aux;
}
void Attach(pid_t pid, unsigned long addr, unsigned long data = 0, bool iswrite = false) {
//First, attach to the process
errno = 0;
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
syslog(LOG_NOTICE, "Stuck at Attach: %s", strerror(errno));
exit(1);
}
//Now, attaching doesn't mean we can read the value straight away
//We have to wait for the process to stop
int status;
//waitpid() returns -1 on failure
if (waitpid(pid, &status, 0) == -1 || !WIFSTOPPED(status)) {
//Failed, read the value of errno or strerror(errno)
syslog(LOG_NOTICE, "Stuck at waitpid: %s", strerror(errno));
exit(1);
}
if (iswrite == true){
memWrite(pid, addr, data);
} else {
memRead(pid, addr);
}
//Now, we have to detach from the process
ptrace(PTRACE_DETACH, pid, NULL, NULL);
}
void memRead(pid_t pid, unsigned long addr) {
errno = 0;
unsigned long value = ptrace(PTRACE_PEEKDATA, pid, addr, NULL);
unsigned long tmp = reverse_bytes(value); // for some reason the bytes show up reversed, so I used this func to re order them
if (value == -1 && errno != 0) {
syslog(LOG_NOTICE, "Bytes reading Failed: %s", strerror(errno));
exit(1);
} else {
syslog(LOG_NOTICE, "Bytes at %Lu: %08X ", addr, tmp);
}
}
void memWrite(pid_t pid, unsigned long addr, unsigned long data) {
syslog(LOG_NOTICE, "----- Original Bytes ----- ");
memRead(pid, addr);
data = reverse_bytes(data);
unsigned long value2 = ptrace(PTRACE_POKETEXT, pid, (void *)addr, (void *)data);
if (value2 == -1 && errno != 0) {
syslog(LOG_NOTICE, "Modification Failed: %s", strerror(errno));
exit(1);
} else {
syslog(LOG_NOTICE, "---- Modified Bytes ----- ");
memRead(pid, addr);
}
//Now, we have to detach from the process
}
Well, it does work now... But I wonder whether why patching only for the first time works. Patching on the offset again fails.
Example:
Orig hex -> 011041E2 (SUB r1, r1, #1)
Patching for first time -> 011081E2 (ADD r1, r1, #1) [Works, function behavior changes]
Patching 2nd time -> 641081E2 (ADD r1, r1, #100) [Patch succeeds but function does not behave accordingly, behavior is similar to when patched for first time]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.