When i execute my code i am getting this error
LPTSTR lpBuffer;
::GetLogicalDriveStrings(1024,lpBuffer);
while(*lpBuffer != NULL)
{
printf("%s\n", lpBuffer); // or MessageBox(NULL, temp, "Test", 0); or whatever
lpBuffer += lstrlen(lpBuffer)+1;
printf("sizeof(lpBuffer) %d\n",lstrlen(lpBuffer));
}
OutPut
C
sizeof(lpBuffer) 3
D
sizeof(lpBuffer) 3
E
sizeof(lpBuffer) 3
F
sizeof(lpBuffer) 0
lpBuffer points to random memory. You need something like this:
LPTSTR lpBuffer = new TCHAR[1025];
edit: Corrected the array size to be 1025 instead of 1024, because the length parameter is 1024. This API requires careful reading.
You are supposed to pass a memory address where the string will be copied. However you have not allocated any space for holding the characters. You need to allocate space before passing it to the GetLogicalDriveStrings function. You can allocate the memory on heap as #Windows programmer suppgested or if the maximum length of the string is known at compile time you can allocate it on stack using TCHAR lpBuffer[1024]; Additinally, you are using printf to print the unicode (may be as it depends on compiler flag). This will not work and will print only first character.
You need to actually pass in a buffer - note that the size of the buffer you pass in needs to be one less than the actual size of the buffer to account for the final terminating '\0' character (I have no idea why the API was designed like that).
Here's a slightly modified version of your example:
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
enum {
BUFSIZE = 1024
};
int _tmain (int argc, TCHAR *argv[])
{
TCHAR szTemp[BUFSIZE];
LPTSTR lpBuffer = szTemp; // point lpBuffer to the buffer we've allocated
szTemp[0] = _T( '\0'); // I'm not sure if this is necessary, but it was
// in the example given for GetLogicalDriveStrings()
GetLogicalDriveStrings( BUFSIZE-1, lpBuffer); // note: BUFSIZE minus 1
while(*lpBuffer != _T('\0'))
{
_tprintf( _T("%s\n"), lpBuffer);
lpBuffer += lstrlen(lpBuffer)+1;
_tprintf( _T("length of lpBuffer: %d\n"),lstrlen(lpBuffer));
}
return 0;
}
Related
I am trying to write a program that calls upon an [external library (?)] (I'm not sure that I'm using the right terminology here) that I am also writing to clean up a provided string. For example, if my main.c program were to be provided with a string such as:
asdfFAweWFwseFL Wefawf JAWEFfja FAWSEF
it would call upon a function in externalLibrary.c (lets call it externalLibrary_Clean for now) that would take in the string, and return all characters in upper case without spaces:
ASDFFAWEWFWSEFLWEFAWFJAWEFFJAFAWSEF
The crazy part is that I have this working... so long as my string doesn't exceed 26 characters in length. As soon as I add a 27th character, I end up with an error that says
malloc(): corrupted top size.
Here is externalLibrary.c:
#include "externalLibrary.h"
#include <ctype.h>
#include <malloc.h>
#include <assert.h>
#include <string.h>
char * restrict externalLibrary_Clean(const char* restrict input) {
// first we define the return value as a pointer and initialize
// an integer to count the length of the string
char * returnVal = malloc(sizeof(input));
char * initialReturnVal = returnVal; //point to the start location
// until we hit the end of the string, we use this while loop to
// iterate through it
while (*input != '\0') {
if (isalpha(*input)) { // if we encounter an alphabet character (a-z/A-Z)
// then we convert it to an uppercase value and point our return value at it
*returnVal = toupper(*input);
returnVal++; //we use this to move our return value to the next location in memory
}
input++; // we move to the next memory location on the provided character pointer
}
*returnVal = '\0'; //once we have exhausted the input character pointer, we terminate our return value
return initialReturnVal;
}
int * restrict externalLibrary_getFrequencies(char * ar, int length){
static int freq[26];
for (int i = 0; i < length; i++){
freq[(ar[i]-65)]++;
}
return freq;
}
the header file for it (externalLibrary.h):
#ifndef LEARNINGC_EXTERNALLIBRARY_H
#define LEARNINGC_EXTERNALLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
char * restrict externalLibrary_Clean(const char* restrict input);
int * restrict externalLibrary_getFrequencies(char * ar, int length);
#ifdef __cplusplus
}
#endif
#endif //LEARNINGC_EXTERNALLIBRARY_H
my main.c file from where all the action is happening:
#include <stdio.h>
#include "externalLibrary.h"
int main() {
char * unfilteredString = "ASDFOIWEGOASDGLKASJGISUAAAA";//if this exceeds 26 characters, the program breaks
char * cleanString = externalLibrary_Clean(unfilteredString);
//int * charDist = externalLibrary_getFrequencies(cleanString, 25); //this works just fine... for now
printf("\nOutput: %s\n", unfilteredString);
printf("\nCleaned Output: %s\n", cleanString);
/*for(int i = 0; i < 26; i++){
if(charDist[i] == 0){
}
else {
printf("%c: %d \n", (i + 65), charDist[i]);
}
}*/
return 0;
}
I'm extremely well versed in Java programming and I'm trying to translate my knowledge over to C as I wish to learn how my computer works in more detail (and have finer control over things such as memory).
If I were solving this problem in Java, it would be as simple as creating two class files: one called main.java and one called externalLibrary.java, where I would have static String Clean(string input) and then call upon it in main.java with String cleanString = externalLibrary.Clean(unfilteredString).
Clearly this isn't how C works, but I want to learn how (and why my code is crashing with corrupted top size)
The bug is this line:
char * returnVal = malloc(sizeof(input));
The reason it is a bug is that it requests an allocation large enough space to store a pointer, meaning 8 bytes in a 64-bit program. What you want to do is to allocate enough space to store the modified string, which you can do with the following line:
char *returnVal = malloc(strlen(input) + 1);
So the other part of your question is why the program doesn't crash when your string is less than 26 characters. The reason is that malloc is allowed to give the caller slightly more than the caller requested.
In your case, the message "malloc(): corrupted top size" suggests that you are using libc malloc, which is the default on Linux. That variant of malloc, in a 64-bit process, would always give you at least 0x18 (24) bytes (minimum chunk size 0x20 - 8 bytes for the size/status). In the specific case that the allocation immediately precedes the "top" allocation, writing past the end of the allocation will clobber the "top" size.
If your string is larger than 23 (0x17) you will start to clobber the size/status of the subsequent allocation because you also need 1 byte to store the trailing NULL. However, any string 23 characters or shorter will not cause a problem.
As to why you didn't get an error with a string with 26 characters, to answer that one would have to see that exact program with the string of 26 characters that does not crash to give a more precise answer. For example, if the program provided a 26-character input that contained 3 blanks, this would would require only 26 + 1 - 3 = 24 bytes in the allocation, which would fit.
If you are not interested in that level of detail, fixing the malloc call to request the proper amount will fix your crash.
I'm quite new to pointers in c.
Here is a snippet of code I'm working on. I am probably not passing the pointer correctly but I can't figure out what's wrong.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
__uint16_t CCrc8();
__uint16_t process_command();
int main () {
//command format: $SET,<0-1023>*<checksum,hex>\r\n
char test_payload[] = "SET,1023*6e";
process_command(test_payload);
return 0;
}
__uint16_t process_command(char *str1) {
char local_str[20];
memcpy(local_str, str1, sizeof(str1));
printf(str1);
printf("\n");
printf(local_str);
}
This results in:
SET,1023*6e
SET,1023
I'm expecting both lines to be the same. Anything past 8 characters is left off.
The only thing I can determine is that the problem is something with sizeof(str1). Any help appreciated.
Update: I've learned sizeof(*char) is 2 on 16bit systems, 4 on 32bit systems and 8 on 64-bit systems.
So how can I use memcpy to get a local copy of str1 when I'm unsure of the size it will be?
sizeof is a compiler keyword. What you need is strlen from #include <string.h>.
The value of sizeof is determinated at compile time. For example sizeof(char[10]) just means 10. strlen on the other hand is a libc function that can determine string length dynamically.
sizeof on a pointer tells you the size of the pointer itself, not of what it points to. Since you're on a 64-bit system, pointers are 8 bytes long, so your memcpy is always copying 8 bytes. Since your string is null terminated, you should use stpncpy instead, like this:
if(stpncpy(local_str, str1, 20) == local_str + 20) {
// too long - handle it somehow
}
That will copy the string until it gets to a NUL terminator or runs out of space in the destination, and in the latter case you can handle it.
From what I understand, a typical buffer overflow attack occurs when an attack overflows a buffer of memory on the stack, thus allowing the attacker to inject malicious code and rewrite the return address on the stack to point to that code.
This is a common concern when using functions (such as sscanf) that blindly copy data from one area to another, checking one for a termination byte:
char str[8]; /* holds up to 8 bytes of data */
char *buf = "lots and lots of foobars"; /* way more than 8 bytes of data */
sscanf(buf, "%s", str); /* buffer overflow occurs here! */
I noticed some sysfs_ops store functions in the Linux kernel are implemented with the Linux kernel's version of the sscanf function:
static char str[8]; /* global string */
static ssize_t my_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
sscanf(buf, "%s", str); /* buf holds more than 8 bytes! */
return size;
}
Suppose this store callback function is set to a writable sysfs attribute. Would a malicious user be able to intentionally overflow the buffer via a write call?
Normally, I would expect guards against buffer overflow attacks -- such as limiting the number of bytes read -- but I see none in a good number of functions (for example in drivers/scsi/scsi_sysfs.c).
Does the implementation of the Linux kernel version of sscanf protect against buffer overflow attacks; or is there another reason -- perhaps buffer overflow attacks are impossible given how the Linux kernel works under the hood?
The Linux sscanf() is vulnerable to buffer overflows; inspection of the source shows this. You can use width specifiers to limit the amount a %s is allowed to write. At some point your str must have had copy_from_user() run on it as well. It is possible the user space to pass some garbage pointer to the kernel.
In the version of Linux you cited, the scsi_sysfs.c does have a buffer overflow. The latest version does not. The committed fix should fix the issue you see.
Short answer:
sscanf, when well called, will not cause buffer overflow, especially in sysfs xxx_store() function. (There are a lot sscanf in sysfs XXX_store() examples), because Linux kernel add a '\0' (zero-terminated) byte after the string (buf[len] = 0;) for your XXX_store() function.
Long answer:
Normally, sysfs are defined to have a strict formatted data. Since you expect 8 bytes at most, it's reasonable to limit the size you get like this:
static char str[8]; /* global string */
static ssize_t my_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
if (size > 8) {
printk("Error: Input size > 8: too large\n");
return -EINVAL;
}
sscanf(buf, "%s", str); /* buf holds more than 8 bytes! */
return size;
}
(Note: use 9 rather than 8, if you expect a 8-bytes string plus '\n')
(Note that you do reject some inputs such as those with many leading white spaces. However, who would send a string with many leading white spaces? Those who want to break your code, right? If they don't follow your spec, just reject them.)
Note that Linux kernel purposely inserts a '\0' at offset len (i.e. buf[len] = 0;) when the user write len bytes to sysfs purposely for safe sscanf, as said in a comment in kernel 2.6: fs/sysfs/file.c:
static int
fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t count)
{
int error;
if (!buffer->page)
buffer->page = (char *)get_zeroed_page(GFP_KERNEL);
if (!buffer->page)
return -ENOMEM;
if (count >= PAGE_SIZE)
count = PAGE_SIZE - 1;
error = copy_from_user(buffer->page,buf,count);
buffer->needs_read_fill = 1;
/* if buf is assumed to contain a string, terminate it by \0,
so e.g. sscanf() can scan the string easily */
buffer->page[count] = 0;
return error ? -EFAULT : count;
}
...
static ssize_t
sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
struct sysfs_buffer * buffer = file->private_data;
ssize_t len;
mutex_lock(&buffer->mutex);
len = fill_write_buffer(buffer, buf, count);
if (len > 0)
len = flush_write_buffer(file->f_path.dentry, buffer, len);
if (len > 0)
*ppos += len;
mutex_unlock(&buffer->mutex);
return len;
}
Higher kernel version keeps the same logic (though already completely rewritten).
Do you know if exist one program or method to see (secuences of)bytes from a text,html file?
Not to see characters, rather see the complete sequence of bytes.
recommendations?
yes, it is called hex editor... Hundreds of those exist out there.
Here are some: http://en.wikipedia.org/wiki/Comparison_of_hex_editors
A common hex editor allows you to view any file's byte sequence.
If you just want to see the existing bytes (without changing them) you can use a hex-dump program, which is much smaller and simpler than a hex editor. For example, here's one I wrote several years ago:
/* public domain by Jerry Coffin
*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
unsigned long offset = 0;
FILE *input;
int bytes, i, j;
unsigned char buffer[16];
char outbuffer[60];
if ( argc < 2 ) {
fprintf(stderr, "\nUsage: dump filename [filename...]");
return EXIT_FAILURE;
}
for (j=1;j<argc; ++j) {
if ( NULL ==(input=fopen(argv[j], "rb")))
continue;
printf("\n%s:\n", argv[j]);
while (0 < (bytes=fread(buffer, 1, 16, input))) {
sprintf(outbuffer, "%8.8lx: ", offset+=16);
for (i=0;i<bytes;i++) {
sprintf(outbuffer+10+3*i, "%2.2X ",buffer[i]);
if (!isprint(buffer[i]))
buffer[i] = '.';
}
printf("%-60s %*.*s\n", outbuffer, bytes, bytes, buffer);
}
fclose(input);
}
return 0;
}
We could initialize a character pointer like this in C.
char *c="test";
Where c points to the first character(t).
But when I gave code like below. It gives segmentation fault.
#include<stdio.h>
#include<stdlib.h>
main()
{
int *i=0;
printf("%d",*i);
}
Also when I give
#include<stdio.h>
#include<stdlib.h>
main()
{
int *i;
i=(int *)malloc(2);
*i=0;
printf("%d",*i);
}
It worked(gave output 0).
When I gave malloc(0), it worked(gave output 0).
Please tell what is happening
Your first example is seg faulting because you are trying to de-reference a null pointer which you have created with the line:
int *i=0;
You can't de-reference a pointer that doesn't point to anything and expect good things to happen. =)
The second code segment works because you have actually assigned memory to your pointer using malloc which you may de-reference. I would think it's possible for you to get values other than zero depending on the memory adjacent to the address you're allocated with malloc. I say this because typically an int is 4 bytes and you've only assigned 2. When de-referencing the int pointer, it should return the value as an int based on the 4 bytes pointed to. In your case, the first 2 bytes being what you received from the malloc and the adjacent 2 bytes being whatever is there which could be anything and whatever it is will be treated as if it was an int. You could get strange behavior like this and you should malloc the size of memory needed for the type you are trying to use/point at.
(i.e. int *i = (int *) malloc(sizeof(int)); )
Once you have the pointer pointing at memory that is of the correct size, you can then set the values as such:
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char *argv[])
{
int *i = (int *)malloc(sizeof(int));
*i = 25;
printf("i = %d\n",*i);
*i = 12;
printf("i = %d\n",*i);
return 0;
}
Edit based on comment:
A pointer points to memory, not to values. When initializing char *ptr="test"; You're not assigning the value of "test", you're assigning the memory address of where the compiler is placing "test" which is placed in your processes data segment and is read only. It you tried to modify the string "test", you program would likely seg-fault. What you need to realize about a char * is that it points at a single (i.e. the first) character in the string. When you de-reference the char *, you will see 1 character and one character only. C uses null terminated strings, and notice that you do not de-reference ptr when calling printf, you pass it the pointer itself and that points at just the first character. How this is displayed depends on the format passed to printf. When printf is passed the '%c' format, it will print the single character ptr points at, if you pass the format '%p' it will print the address that ptr points. To get the entire string, you pass '%s' as the format. What this makes printf do is to start at the pointer you passed in and read each successive byte until a null is reached. Below is some code that demonstrates these.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[])
{
// Initialize to data segement/read only string
char *ptr = "test";
printf("ptr points at = %p\n", ptr); // Prints the address ptr points to
printf("ptr dereferenced = %c\n", *ptr); // Prints the value at address ptr
printf("ptr value = %s\n", ptr); // Prints the string of chars pointed to by ptr
// Uncomment this to see bad behavior!
// ptr[1] = 'E'; // SEG FAULT -> Attempting to modify read-only memory
printf("--------------------\n");
// Use memory you have allocated explicitly and can modify
ptr = malloc(10);
strncpy(ptr, "foo", 10);
printf("ptr now points at = %p\n", ptr); // Prints the address ptr points to
printf("ptr dereferenced = %c\n", *ptr); // Prints the value at address ptr
printf("ptr value = %s\n", ptr); // Prints the string of chars pointed to by ptr
ptr[1] = 'F'; // Change the second char in string to F
printf("ptr value (mod) = %s\n", ptr);
return 0;
}