Is it possible to use PTRACE_SETREGS to change the execution sequence of a process? - ptrace

Is it possible to use PTRACE_SETREGS to change the execution sequence of a process?
I'm saving the process register file at a point of the process execution and I want to use it later to set the current register file of the process (to repeat the execution again at this point).
below is the code I'm trying to use, but it does not work. can someone explain to me what is wrong with it or what I misunderstand about the ptrace?
#include<stdio.h>
#include<sys/ptrace.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/reg.h>
#include<sys/user.h>
#include<sys/syscall.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
pid_t app1;
int status;
int entry =1; //used to check the system call entry or exit
struct user_regs_struct app1_regs, prev_sys_regs;
int flag=1;
long app1_syscall;
if(argc < 2)
{
printf("Usage: %s <pid to be traced>\n", argv[0], argv[1]);
exit(1);
}
app1 = atoi(argv[1]);
ptrace(PTRACE_ATTACH, app1, NULL, NULL);
while (1){
waitpid(app1,&status,0);
app1_syscall = ptrace(PTRACE_PEEKUSER, app1, 4 * ORIG_EAX, NULL);
ptrace(PTRACE_GETREGS, app1, NULL, &app1_regs);
if(entry){//system call entry
entry = 0;
printf("Instruction Pointer:0x%.8lx, Stack Pointer: 0x%.8lx, orig_eax: 0x%.8lx, eax: 0x%.8lx, ebx: 0x%.8lx, ecx: 0x%.8lx, edx: 0x%.8lx, esi: 0x%.8lx, edi:0x%.8lx,ebp:0x%.8lx\n",app1_regs.eip, app1_regs.esp, app1_regs.orig_eax, app1_regs.eax, app1_regs.ebx, app1_regs.ecx, app1_regs.edx, app1_regs.esi, app1_regs.edi, app1_regs.ebp);
if(app1_syscall == SYS_write && flag ==1){
flag=0; //I want to do this only once
//here I'm setting the current registers of the process with the previous one to repeat the execution from previous point
ptrace(PTRACE_SETREGS, app1, NULL, &prev_sys_regs);
}
}
else{ //system call exit
entry = 1;
if (flag ==1)
prev_sys_regs = app1_regs;
if(WIFEXITED(status))
return 0;
}
ptrace(PTRACE_SYSCALL, app1, NULL, NULL);
}
return 0;
}

Related

Return value of call_usermodehelper() is not correct

I am calling a user-space application, /usr/bin/myapp, from a Linux Kernel Module using call_usermodehelper(). The myapp returns 2228 when it exits. I should receive same value i.e 2228 as a return value of call_usermodehelper() in the kernel module. However, I am receiving a different value, that is 46080.
My question is, why I don't receive the value I return from myapp as the return value of call_usermodehelper()? Note, myapp executes successfully when I call it from kernel module using call_usermodehelper(). I don't return 0 as a success code. I return 2228 on exit.
Here is the sample code:
user-space's application code:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("%s called successfully\n", argv[0]);
return 2228;
}
Kernel Module's Code:
int call_userspaceapp()
{
int ret = -EPERM;
char *argv[] = {"/usr/bin/myapp", "11", "22", "33", NULL};
char *envp[] = {"HOME=/", NULL};
ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
printk("%s returns value %d", argv[0], ret);
return ret;
}
However, I am receiving a different value, that is 46080.
Exit status has 8 bits and return value is just like waitpid return value. See userspace definition of WEXITSTATUS to access the exit status, which is 46080 >> 8 = 180, which is equal to the returned exit status 2228 % 256 = 180. Here drbd_nl.c I found an example of call_usermodehelper that also accesses the exit status with (ret >> 8) && 0xff, just like WEXITSTATUS.

GetThreadSelectorEntry throwing ERROR_NOT_SUPPORTED for x64 App

I trying to write a very simple app to debug a Win32 64-bit app. My end goal is to get the TIB and PEB of the remote thread, but for some reason the way I did this on 32-bit app is not working for 64-bit ones (Aside from looking at Esp vs Rsp and checking SegFs vs SegGs). The code I'm trying to use is here:
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
int main(int argc, char *argv[]){
LDT_ENTRY entry;
DWORD pid;
HANDLE hThread;
HANDLE hSnapshot;
CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL;
if(argc < 2){
printf("Usage: %s PID\n", argv[0]);
exit(1);
}
pid = atoi(argv[1]);
THREADENTRY32 te32;
te32.dwSize = sizeof(te32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
while(Thread32Next(hSnapshot, &te32)){
if(pid == te32.th32OwnerProcessID){
hThread = OpenThread(THREAD_ALL_ACCESS, 0, te32.th32ThreadID);
if(!hThread)
exit(1);
if(SuspendThread(hThread) == (DWORD) -1)
exit(1);
if(!GetThreadContext(hThread, &context))
exit(1);
printf("Rsp = 0x%x\n", context.Rsp);
if(!GetThreadSelectorEntry(hThread, context.SegGs, &entry)){
LPSTR buff = NULL;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL);
printf("Error: %s\n", buff); //ERROR_NOT_SUPPORTED 50 0x32 The request is not supported.
LocalFree(buff);
exit(1);
}
}
}
CloseHandle(hSnapshot);
return 0;
}
but it's always throwing an error at "GetThreadSelectorEntry". The error code that's thrown is ERROR_NOT_SUPPORTED: The request is not supported.
I am not able to understand why it's not supported. Does anyone know why?
[EDIT]
Okay GetThreadSelectorEntry is not available to x86_64 processes, does anyone know how I can get the TIB/PEB addresses of a remote process?

Passing input with netcat to a simple server

I am trying to write an Ruby script to pass strings to a simple server running in a VM and I am stuck at passing the strings without creating inifinite loops in my server program.
The Content of the Server(written in C):
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORTNO 12346
int h=0,b=0,p=0;
#define BUFFER_SIZE 512
int checksec(FILE* f){
FILE* key;
char buf[1024];
if(h&b&p){
key=fopen("easy_key","r");
fread(buf,1024,1,key);
fprintf(f,"%s",buf);
fclose(key);
return 0;
}
return 1;
}
void hekers(FILE* f){
volatile int zeroWeekend;
char buf[32];
fprintf(f,"So you want to be an 31337 Hax0r?\n");
fgets(buf,40,f);
switch(strcmp("y3$\n",buf)){
case 0:
fprintf(f,"First you must get power\n");
break;
default:
fprintf(f,"Well then go away\n");
break;
}
if(zeroWeekend==0xcafebabe){
h=1;
}
return;
}
void batmenss(FILE* f){
volatile int batsignet;
char buf[32];
fprintf(f,"So you want to be the batman?\n");
fgets(buf,40,f);
switch(strcmp("YESSSSSSS\n",buf)){
case 0:
fprintf(f,"First you must get rich\n");
break;
default:
fprintf(f,"Well then go away\n");
break;
}
if(batsignet==0x12345678){
b=1;
}
return;
}
void pokemans(FILE* f){
volatile int pikachy;
char buf[32];
fprintf(f,"So you want to be the best there ever was?\n");
fgets(buf,40,f);
switch(strcmp("catchemall\n",buf)){
case 0:
fprintf(f,"First you must get respect\n\n");
break;
default:
fprintf(f,"Well then go away\n");
break;
}
if(pikachy==0xfa75beef){
p=1;
}
return;
}
void readInput(int sock){
int msg;
char choice[4];
char buffer[BUFFER_SIZE];
FILE* fptr = fdopen(sock, "r+");
char* prompt="Do you want to be a?\n"
"1.) Pokemon Master\n"
"2.) Elite Hacker\n"
"3.) The Batman\n";
while(checksec(fptr)){
fprintf(fptr,"%s",prompt);
fgets(choice,4,fptr);
switch(choice[0]){
case '1':
pokemans(fptr);
break;
case '2':
hekers(fptr);
break;
case '3':
batmenss(fptr);
break;
default:
fprintf(fptr,"\nThat is not one of the choices\n");
fflush(fptr);
}
}
fprintf(fptr, "%s", buffer);
fflush(fptr);
fclose(fptr);
return;
}
int main(int argc, char *argv[])
{
char buffer[BUFFER_SIZE];
int sockfd, newsockfd, portno, pid;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
/*
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
*/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0){
perror("ERROR opening socket");
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
//portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
serv_addr.sin_port = htons(PORTNO);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0){
perror("ERROR on binding");
exit(1);
}
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1) {
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
perror("ERROR on accept");
pid = fork();
if (pid < 0)
perror("ERROR on fork");
if (pid == 0) {
close(sockfd);
readInput(newsockfd);
return;
}
else close(newsockfd);
waitpid(-1,NULL,WNOHANG);
} /* end of while */
close(sockfd);
return 0; /* we never get here */
}
When I connect to the server, it looks like this:
user#DESKTOP-LINUX:~/Documents/tob/ctf/exploits/binary1_workshop/easy$ nc 192.168.178.40 12346
Do you want to be a?
1.) Pokemon Master
2.) Elite Hacker
3.) The Batman
Now the Program waits for an input and another string will be printed and then the Program waits for another input and so on...
Now the real problem comes when I try to use a Ruby Script that should dictate the input that the Program should get.
I tried it with this Ruby Script (Filename: script.rb):
#!/usr/bin/env ruby
firstinput = "1"
puts select + "\r\n"
secondinput = "2"
puts secondinput + "\r\n"
And executed it with this command:
user#DESKTOP-LINUX:~/Documents/Code/binary1_workshop_exploits$ ./script.rb | nc 192.168.178.40 12346
But the output is just an infinite loop of the "main menu"...
How do I fix this problem?
P.S. I am running Ubuntu 14.04 64-Bit and the VM with the Server is running Ubuntu 14.04 32-Bit

C shell printing output infinitely without stopping at gets()

I am trying to use the SIGCHLD handler but for some reason it prints of the command I gave infinitely. If I remove the struct act it works fine.
Can anyone take a look at it, I am not able to understand what the problem is.
Thanks in advance!!
/* Simplest dead child cleanup in a SIGCHLD handler. Prevent zombie processes
but dont actually do anything with the information that a child died. */
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
typedef char *string;
/* SIGCHLD handler. */
static void sigchld_hdl (int sig)
{
/* Wait for all dead processes.
* We use a non-blocking call to be sure this signal handler will not
* block if a child was cleaned up in another part of the program. */
while (waitpid(-1, NULL, WNOHANG) > 0) {
}
}
int main (int argc, char *argv[])
{
struct sigaction act;
int i;
int nbytes = 100;
char my_string[nbytes];
string arg_list[5];
char *str;
memset (&act, 0, sizeof(act));
act.sa_handler = sigchld_hdl;
if (sigaction(SIGCHLD, &act, 0)) {
perror ("sigaction");
return 1;
}
while(1){
printf("myshell>> ");
gets(my_string);
str=strtok(my_string," \n");
arg_list[0]=str;
i =1;
while ( (str=strtok (NULL," \n")) != NULL){
arg_list[i]= str;
i++;
}
if (i==1)
arg_list[i]=NULL;
else
arg_list[i+1]=NULL;
pid_t child_pid;
child_pid=fork();
if (child_pid == (pid_t)-1){
printf("ERROR OCCURED");
exit(0);
}
if(child_pid!=0){
printf("this is the parent process id is %d\n", (int) getpid());
printf("the child's process ID is %d\n",(int)child_pid);
}
else{
printf("this is the child process, with id %d\n", (int) getpid());
execvp(arg_list[0],arg_list);
printf("this should not print - ERROR occured");
abort();
}
}
return 0;
}
I haven't run your code, and am merely hypothesizing:
SIGCHLD is arriving and interrupting fgets (I'll just pretend you didn't use gets). fgets returns before actually reading any data, my_string contains the tokenized list that it had on the previous loop, you fork again, enter fgets, which is interrupted before reading any data, and repeat indefinitely.
In other words, check the return value of fgets. If it is NULL and has set errno to EINTR, then call fgets again. (Or set act.sa_flags = SA_RESTART.)

Getting process base address in Mac OSX

I'm trying to read the memory of a process using task_for_pid / vm_read.
uint32_t sz;
pointer_t buf;
task_t task;
pid_t pid = 9484;
kern_return_t error = task_for_pid(current_task(), pid, &task);
vm_read(task, 0x10e448000, 2048, &buf, &sz);
In this case I read the first 2048 bytes.
This works when I know the base address of the process (which I can find out using gdb "info shared" - in this case 0x10e448000), but how do I find out the base address at runtime (without looking at it with gdb)?
Answering my own question. I was able to get the base address using mach_vm_region_recurse like below. The offset lands in vmoffset. If there is another way that is more "right" - don't hesitate to comment!
#include <stdio.h>
#include <mach/mach_init.h>
#include <sys/sysctl.h>
#include <mach/mach_vm.h>
...
mach_port_name_t task;
vm_map_offset_t vmoffset;
vm_map_size_t vmsize;
uint32_t nesting_depth = 0;
struct vm_region_submap_info_64 vbr;
mach_msg_type_number_t vbrcount = 16;
kern_return_t kr;
if ((kr = mach_vm_region_recurse(task, &vmoffset, &vmsize,
&nesting_depth,
(vm_region_recurse_info_t)&vbr,
&vbrcount)) != KERN_SUCCESS)
{
printf("FAIL");
}
Since you're calling current_task(), I assume you're aiming at your own process at runtime. So the base address you mentioned should be the dynamic base address, i.e. static base address + image slide caused by ASLR, right? Based on this assumption, you can use "Section and Segment Accessors" to get the static base address of your process, and then use the dyld functions to get the image slide. Here's a snippet:
#import <Foundation/Foundation.h>
#include </usr/include/mach-o/getsect.h>
#include <stdio.h>
#include </usr/include/mach-o/dyld.h>
#include <string.h>
uint64_t StaticBaseAddress(void)
{
const struct segment_command_64* command = getsegbyname("__TEXT");
uint64_t addr = command->vmaddr;
return addr;
}
intptr_t ImageSlide(void)
{
char path[1024];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) != 0) return -1;
for (uint32_t i = 0; i < _dyld_image_count(); i++)
{
if (strcmp(_dyld_get_image_name(i), path) == 0)
return _dyld_get_image_vmaddr_slide(i);
}
return 0;
}
uint64_t DynamicBaseAddress(void)
{
return StaticBaseAddress() + ImageSlide();
}
int main (int argc, const char *argv[])
{
printf("dynamic base address (%0llx) = static base address (%0llx) + image slide (%0lx)\n", DynamicBaseAddress(), StaticBaseAddress(), ImageSlide());
while (1) {}; // you can attach to this process via gdb/lldb to view the base address now :)
return 0;
}
Hope it helps!

Resources