Segmentation fault when trying to read python process memory on Mac OS - python

I was trying to figure out how the Mach VM Api works as there is almost 0 documentation around it and to do that I was messing around with reading/writing to other processes' memory.
To start I basically created a c program that constantly printed a string and its address. Then I used this program to try modifying the string mid execution and it worked fine:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <libproc.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#define EXIT_ON_MACH_ERROR(msg, retval) \
if (kr != KERN_SUCCESS) { mach_error(msg ":" , kr); exit((retval)); }
uint32_t* get_pids(uint16_t* size) {
// Gets all PIDS on the system to locate specific PID later. Probably inefficient
// but I don't care
uint32_t number_of_pids = proc_listpids(1, 0, NULL, 0);
uint32_t* buffer = malloc(sizeof(uint32_t) * number_of_pids);
uint8_t return_code = proc_listpids(1, 0, buffer, sizeof(buffer) * number_of_pids);
uint16_t sum = 0;
for(int i = 0; i < number_of_pids; i++) {
if(buffer[i] != 0) {
sum++;
}
}
uint32_t* final = malloc(sizeof(uint32_t) * sum);
for(int i = 0, t = 0; i < number_of_pids; i++) {
if(buffer[i]) {
final[t++] = buffer[i];
}
}
*size = sum;
return final;
}
int main() {
// Locate correct PID according to process name
uint16_t size;
uint32_t* pids = get_pids(&size);
uint16_t maxpathlength = 1024;
uint16_t path_size = maxpathlength * 4;
char path_buffer[path_size];
uint32_t process_pid = 0;
for(int i = 0; i < size; i++) {
memset(path_buffer, '\0', sizeof(path_buffer));
uint8_t return_code = proc_pidpath(pids[i], path_buffer, path_size);
if(strstr(path_buffer, "Python")) {
printf("%d\n", i);
process_pid = pids[i];
}
//printf("PID: %d, Process: %s\n", pids[i], path_buffer);
}
printf("%d\n", process_pid);
struct proc_taskallinfo pro_info;
uint32_t status = proc_pidinfo(process_pid, PROC_PIDTASKALLINFO, 0, &pro_info, sizeof(pro_info));
printf("Python PID: %d\n", process_pid);
printf("Self PID: %d\n", mach_host_self());
mach_port_t port = 0;
kern_return_t kr = task_for_pid(mach_task_self(), process_pid, &port);
EXIT_ON_MACH_ERROR("task_for_pid", kr);
printf("Port: %d\n\n\n", port);
// STUFF
mach_vm_address_t address = 0x102d4b770;
mach_vm_address_t address_a = 0x102d4b770;
char data[50] = "wow";
vm_offset_t buf;
mach_msg_type_number_t sz;
// MEMORY DEALLOCATION
kern_return_t suc = mach_vm_deallocate(port, (mach_vm_address_t) address, (mach_vm_size_t) 1000);
if (suc!=KERN_SUCCESS)
{
printf("mach_vm_deallocate() failed with message %s!\n", mach_error_string(suc));
}
// MEMORY ALLOCATION
kern_return_t all_suc = mach_vm_allocate(port, (mach_vm_address_t *) &address_a, (vm_size_t) 26, false);
if (all_suc!=KERN_SUCCESS)
{
printf("mach_vm_allocate() failed with message %s!\n", mach_error_string(all_suc));
}
// WRITE TO MEMORY
kern_return_t success = mach_vm_write(port, (vm_address_t) address, (vm_address_t)data, 26);
if (success!=KERN_SUCCESS)
{
printf("mach_vm_write() failed with message %s!\n", mach_error_string(success));
}
// READ FROM MEMORY
kern_return_t read_success = mach_vm_read(port, (vm_address_t) 0x6000018c4030, 26, &buf, &sz);
if (read_success!=KERN_SUCCESS)
{
printf("mach_vm_read() failed with message %s!\n", mach_error_string(read_success));
}
char * newstr = (char *) buf;
printf("%s\n", newstr);
return 0;
}
address and address_a were entered manually after figuring out the variable's address. However, when I tried this with a python process where I again just constantly printed out the string and address, I got the following error message the instant I ran the code above:
zsh: segmentation fault python3 strtest.py
I have no knowledge about CPython, so even after playing around a bit and trying to make it work, nothing happened. How can I make this work even on programs? I know its possible as Bit-Slicer made it work but I wasn't able to found out how.

Related

How to get Device Power State of an Adapter?

I'm looking for a programmatic way of querying an Display Adapter's current power state (d-state) in Windows. It's not a USB device or ACPI device. I couldn't find much on how I could access the current d-state through cmd line or an API. It could also be seen in the device manager adapter's detail info.
Display Adapter's detail tab showing the device power state
logic that i have written :
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
#pragma comment (lib, "SetupAPI.lib")
int DeviceManager::GetDeviceDriverPowerData() {
int res = 0;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData = { sizeof(DeviceInfoData) };
// get device class information handle
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_ADAPTER, 0, 0, DIGCF_PRESENT /*| DIGCF_PROFILE*/);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
res = GetLastError();
return res;
}
// enumerute device information
DWORD required_size = 0;
for (int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++)
{
DWORD DataT;
CM_POWER_DATA cmPowerData = { 0 };
// get device description information
if (!SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData, SPDRP_DEVICE_POWER_DATA, &DataT, (PBYTE)&cmPowerData, sizeof(cmPowerData), &req_bufsize))
{
res = GetLastError();
continue;
}
printf("PowerState:%d.\n", cmPowerData.PD_MostRecentPowerState);
}
return 0;
}
but it doesn't work .

How to save an array from serial port to arduino (Save in EEPROM memory)

I trying to implement a project and I'm running in some issues. Well, I need to send an array from Python to arduino and save the array at EEPROM memory. I did some tests to save just ONE element at EEPROM memory and it worked preety well.
But, When I try to send the whole array, the data at EEPROM are ALL wrong. I think maybe it's because the time needed to write data in EEPROM memory.
Python
for i in range(0,156):
conexao.write(str(eeprom[i]).encode('utf-8'))
time.sleep(2)
conexao.close()
Arduino
#include <EEPROM.h>
String c;
int aux=0;
const int STARTING_EEPROM_ADDRESS = 0;
const int ARRAY_SIZE = 156;
int numbers[ARRAY_SIZE];
void writeIntArrayIntoEEPROM(int address, int numbers[],int element){
int x = element;
int addressIndex = address;
EEPROM.write(addressIndex, numbers[x] >> 8);
EEPROM.write(addressIndex + 1, numbers[x] & 0xFF);
while(Serial.read() >= 0); // I hope it clean the serial buffer
}
void readIntArrayFromEEPROM(int address, int numbers[], int arraySize)
{
int addressIndex = address;
for (int i = 0; i < arraySize; i++)
{
numbers[i] = (EEPROM.read(addressIndex) << 8) + EEPROM.read(addressIndex + 1);
addressIndex += 2;
}
}
void setup() {
Serial.begin(9600);
int newNumbers[ARRAY_SIZE];
readIntArrayFromEEPROM(STARTING_EEPROM_ADDRESS, newNumbers, ARRAY_SIZE);
for (int i = 0; i < ARRAY_SIZE; i++)
{
Serial.println(newNumbers[i]);
}
// Serial.println((EEPROM.read(0) << 8) + EEPROM.read(0 + 1));
}
void loop() {
while (Serial.available()>0){
for (int i=0; i < ARRAY_SIZE; i++) {
c=Serial.readStringUntil('\n');
numbers[i]=c.toInt();
writeIntArrayIntoEEPROM(aux, numbers[i], i);
aux +=2;
}
}
}

Linux epoll syscall, waiting though data available

Testing Linux syscall epoll using a simple parent-child program.
Expected behaviour
As the child writes a no every second, the parent should read it from the pipe and write a no every second to stdout.
Actual behaviour
The parent waits till the child writes all the nos, and then reads all data from pipe and writes to stdout. Verified by doing strace on parent. It blocks in epoll_wait.
please check README in github more information
Parent
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <error.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define NAMED_FIFO "aFifo"
static void set_nonblocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
perror("fcntl()");
return;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
perror("fcntl()");
}
}
void errExit(char *msg) {
perror(msg);
exit(-1);
}
void printArgs(char **argv,char **env) {
for(int i=0;argv[i];i++)
printf("argv[%d]=%s\n",i,argv[i]);
for(int i=0;env[i];i++)
printf("env[%d]=%s\n",i,env[i]);
}
void PrintNos(short int max,char *name) {
int fifo_fd,rVal;
int bSize=2;
char buffer[bSize];
fifo_fd = open(NAMED_FIFO,O_RDONLY);
if(fifo_fd<0)
errExit("open");
for(short int i=0;i<max;i++) {
rVal = read(fifo_fd,buffer,bSize);
if(rVal != bSize)
errExit("read");
printf("%03d\n",i);
}
}
int main(int argc, char *argv[],char *env[]) {
//int pipe_fds_child_stdin[2] ;
int pipe_fds_child_stdout[2] ;
pid_t child_id ;
//if( pipe(pipe_fds_child_stdin) < 0 )
// errExit("pipe");
if( pipe(pipe_fds_child_stdout) < 0 )
errExit("pipe");
child_id = fork();
if( child_id > 0 ) {
const int MAX_POLL_FDS = 2;
const int BUF_SIZE = 4;
size_t readSize;
char buf[BUF_SIZE];
int status;
int epoll_fd;
int nfds ;
struct epoll_event e_e, e_events[MAX_POLL_FDS];
memset(e_events,'\0',sizeof(e_events));
memset(&e_e,'\0',sizeof(e_e));
//close(pipe_fds_child_stdin[0]);
close(pipe_fds_child_stdout[1]);
epoll_fd = epoll_create1(0);
if(epoll_fd < 0)
errExit("epoll_create1");
e_e.data.fd = pipe_fds_child_stdout[0];
e_e.events = EPOLLIN;
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_fds_child_stdout[0], &e_e) < 0)
errExit("epoll_ctl");
while(1) {
nfds = epoll_wait(epoll_fd, e_events,MAX_POLL_FDS,-1);
if( nfds < 0)
errExit("epoll_wait");
for(int i=0;i<nfds;i++) {
if( e_events[i].data.fd == pipe_fds_child_stdout[0]) {
if( e_events[i].events & EPOLLIN) {
readSize = read(pipe_fds_child_stdout[0],buf,BUF_SIZE);
if( readSize == BUF_SIZE ) {
write(STDOUT_FILENO,buf,BUF_SIZE);
} else if(readSize == 0) { // eof
errExit("readSize=0");
} else {
errExit("read");
}
} else if( e_events[i].events & EPOLLHUP) {
printf("got EPOLLHUP on pipefd\n");
wait(&status);
exit(0);
} else {
errExit("Unexpected event flag returned by epoll_wait on waited fd");
}
} else {
errExit("epoll_wait returned non-awaited fd");
}
}
}
} else if( child_id == 0 ) {
close(0);
close(1);
//close(pipe_fds_child_stdin[1]);
close(pipe_fds_child_stdout[0]);
//dup2(pipe_fds_child_stdin[0],0);
dup2(pipe_fds_child_stdout[1],1);
execvpe(argv[1],&(argv[1]),env);
//PrintNos(100,"P");
//errExit("execvp");
} else {
errExit("fork");
}
}
Child
import sys
import time
import os
#f=open("aFifo",'r')
for x in range(10):
#try:
# val = f.read(2)
#except Exception as e:
# raise
time.sleep(1)
print(f'{x:03d}')
This is due to python buffering, which can be disabled by passing -u option to python.
After much searching and research, understood that this is due to pipe buffer. Though the client writes, it is in pipe buffer. Only after the pipe buffer is full, the kernel sends ready event on that descriptor. The minimum is pagesize, kernel doesn't allow to set below that. But it can be increased. Got to this, by changing from epoll to poll/select. After changing to poll/select the behaviour was same. Blocking though data was available in pipe.
import fcntl
import os
F_SETPIPE_SZ=1031
fds = os.pipe()
for i in range(5):
print(fcntl.fcntl(fds[0],F_SETPIPE_SZ,64))
$ python3.7 pipePageSize.py
4096
4096
This is the modified client. Appropriate changes in server too.
import time
pageSize=1024*8
for x in range(100):
time.sleep(0.5)
print(f'{x:-{pageSize}d}')

Python ctypes cannot get long string value returned from .so file

I am learning C and trying to import a .so into my python file for higher performance by using a python package ctypes. So everything going well until I had a hard time when trying to get a string returned from .so file.
C code:
char *convert_to_16(char *characters, int n){
char sub_buffer[3];
char code[3];
char *buffer = (char*)malloc(sizeof(characters) * 2);
for(int i=0; i < n; i++){
strncpy(code, characters+i, 1);
sprintf(sub_buffer, "%x", *code);
strncat(buffer, sub_buffer, 2);
}
return buffer;
}
// main() only for test
int main(){
char param[] = "ABCDEFGHTUIKLL";
printf("%s\n", param);
int length = strlen(param);
printf("%s\n", convert_to_16(param, length));
}
It runs well with output:
41424344454647485455494b4c4c
Python code :
c_convert_to_16 = ctypes.CDLL('./convert_to_16.so').convert_to_16
c_convert_to_16.restype = ctypes.c_char_p
a_string = "ABCDEFGHTUIKLL"
new_16base_string = c_convert_to_16(a_string, len(a_string))
print new_16base_string
It runs but only returns two characters:
41
I read the official doc and set restype as ctypes.c_char_p, and try to set it to other values. But it seems it's the only option, just oddly only two characters were returned.
Is it the problem of my ctypes configuration or my C wasn't written correctly?
Many thanks.
I don't know much about ctypes in python but you should create your string like that c_char_p("ABCDEFGHTUIKLL").
And maybe tell what argument take your function c_convert_to_16.argtypes = [c_char_p, c_size_t]
This will fix your undefined behavior in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *convert_to_16(char const *array, size_t const len);
char *convert_to_16(char const *array, size_t const len) {
size_t const len_buffer = len * 2 + 1;
char *buffer = malloc(len_buffer);
if (buffer == NULL) {
return NULL;
}
size_t used = 0;
for (size_t i = 0; i < len; i++) {
if (len_buffer < used || len_buffer - used < 3) {
free(buffer);
return NULL;
}
int ret = snprintf(buffer + used, 3, "%.2x", (unsigned char)array[i]);
if (ret != 2) {
free(buffer);
return NULL;
}
used += 2;
}
return buffer;
}
int main(void) {
char const param[] = "ABCDEFGHTUIKLL";
printf("%s\n", param);
char *ret = convert_to_16(param, sizeof param - 1);
if (ret != NULL) {
printf("%s\n", ret);
}
free(ret);
}

Import error in Python for libcurl library

I have written a program in c using libcurl to load url and send the return value to Python (I am passing 2 integer value from Python to C. i am yet to enhance the code, currently trying the logic and variable accessibility between Python and C.). I am able to compile the program successfully. When i load the module in Python i am getting error saying "undefined symbol: curl_easy_getinfo". Please let me know how to fix the issue.
Code:
#include <Python.h>
#include <stdio.h>
#include <time.h>
#include <stdio.h>
#include <pthread.h>
#include <curl/curl.h>
#define NUMT 4
/*
List of URLs to fetch.
If you intend to use a SSL-based protocol here you MUST setup the OpenSSL
callback functions as described here:
http://www.openssl.org/docs/crypto/threads.html#DESCRIPTION
*/
const char * const urls[NUMT]= {
"http://www.google.com",
"http://www.yahoo.com/",
"http://www.haxx.se/done.html",
"http://www.haxx.se/"
};
#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL 3
struct myprogress {
double lastruntime;
curl_off_t totdnld;
void *url;
CURL *curl;
};
static PyObject *foo1_add(PyObject *self, PyObject *args)
{
int a;
int b;
int s;
if (!PyArg_ParseTuple(args, "ii", &a, &b))
{
return NULL;
}
s = sum (a, b);
return Py_BuildValue("i", s);
// return Py_BuildValue("i", a + b);
}
static PyMethodDef foo1_methods[] = {
{ "add", (PyCFunction)foo1_add, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
PyMODINIT_FUNC initfoo1()
{
Py_InitModule3("foo1", foo1_methods, "My first extension module.");
}
int sum(int x, int y) {
int z;
z = x + y;
z = geturl (x, y);
return (z);
}
/* this is how the CURLOPT_XFERINFOFUNCTION callback works */
#ifdef 0
static int xferinfo(void *p,
curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow)
{
struct myprogress *myp = (struct myprogress *)p;
CURL *curl = myp->curl;
double curtime = 0;
curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &curtime);
/* under certain circumstances it may be desirable for certain functionality
to only run every N seconds, in order to do this the transaction time can
be used */
if((curtime - myp->lastruntime) >= MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL) {
myp->lastruntime = curtime;
fprintf(stderr, "TOTAL TIME: %f \r\n", curtime);
}
if (dlnow > 0) {
fprintf(stderr, "UP: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T
" DOWN: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T
"\r\n",
ulnow, ultotal, dlnow, dltotal);
}
myp->totdnld = myp->totdnld + dlnow;
if (dlnow > 0) {
fprintf(stderr, "TOTAL Download: %" CURL_FORMAT_CURL_OFF_T " url is: %s \r\n", myp->totdnld, myp->url);
}
// if(dlnow > STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES)
// return 1;
return 0;
}
#endif
/* for libcurl older than 7.32.0 (CURLOPT_PROGRESSFUNCTION) */
static int older_progress(void *p,
double dltotal, double dlnow,
double ultotal, double ulnow)
{
return xferinfo(p,
(curl_off_t)dltotal,
(curl_off_t)dlnow,
(curl_off_t)ultotal,
(curl_off_t)ulnow);
}
static void *pull_one_url(void *url)
{
CURL *curl;
CURLcode res = CURLE_OK;
struct myprogress prog;
curl = curl_easy_init();
if(curl) {
prog.lastruntime = 0;
prog.curl = curl;
prog.url = url;
prog.totdnld = (curl_off_t) 0;
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, older_progress);
/* pass the struct pointer into the progress function */
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &prog);
#ifdef 0
#if LIBCURL_VERSION_NUM >= 0x072000
/* xferinfo was introduced in 7.32.0, no earlier libcurl versions will
compile as they won't have the symbols around.
If built with a newer libcurl, but running with an older libcurl:
curl_easy_setopt() will fail in run-time trying to set the new
callback, making the older callback get used.
New libcurls will prefer the new callback and instead use that one even
if both callbacks are set. */
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo);
/* pass the struct pointer into the xferinfo function, note that this is
an alias to CURLOPT_PROGRESSDATA */
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog);
#endif
#endif
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
fprintf(stderr, "%s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
return NULL;
}
/*
int pthread_create(pthread_t *new_thread_ID,
const pthread_attr_t *attr,
void * (*start_func)(void *), void *arg);
*/
int geturl(int x, int y)
{
pthread_t tid[NUMT];
int i;
int error;
/* Must initialize libcurl before any threads are started */
curl_global_init(CURL_GLOBAL_ALL);
for(i=0; i< NUMT; i++) {
error = pthread_create(&tid[i],
NULL, /* default attributes please */
pull_one_url,
(void *)urls[i]);
if(0 != error)
fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
else
fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
}
/* now wait for all threads to terminate */
for(i=0; i< NUMT; i++) {
error = pthread_join(tid[i], NULL);
fprintf(stderr, "Thread %d terminated\n", i);
}
return (x * y);
}
Command used for compilation:
gcc -lcurl -lpthread -shared -I/usr/include/python2.7 -fPIC sample.c –o add.so
Error:
>>> import foo1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: ./foo1.so: undefined symbol: curl_easy_perform
>>>
Try moving -lcurl and -lpthread to after sample.c in your compilation command. The linker resolves symbols in left-to-right order, so references from sample.c (e.g., curl_easy_getinfo) will be resolved from libraries specified after it.
It's better to use -pthread than -lpthread by the way. It sets preprocessor flags to make some functions reentrant for example.

Categories