C kernel- printing string not working - c

I am making a C kernel from scratch, and I literally just copied this code off of a website because my code wasn't working so I was confused.
void kmain(void)
{
const char *str = "my first kernel";
char *vidptr = (char*)0xb8000; //video mem begins here.
unsigned int i = 0;
unsigned int j = 0;
/* this loops clears the screen
* there are 25 lines each of 80 columns; each element takes 2 bytes */
while(j < 80 * 25 * 2) {
/* blank character */
vidptr[j] = ' ';
/* attribute-byte - light grey on black screen */
vidptr[j+1] = 0x07;
j = j + 2;
}
j = 0;
/* this loop writes the string to video memory */
while(str[j] != '\0') {
/* the character's ascii */
vidptr[i] = str[j];
/* attribute-byte: give character black bg and light grey fg */
vidptr[i+1] = 0x07;
++j;
i = i + 2;
}
return;
}
When I run my kernel, it prints an S to the screen and nothing else. I know my kernel is booting, because if I do
vidptr[0] = 'h';
vidptr[2] = 'e';
vidptr[4] = 'l';
vidptr[6] = 'l';
vidptr[8] = 'o';
it works as expected. What is happening?
EDIT: It might be something with my code that loads the kernel (might not have set up some of the registers) so I will just look into grub and other things.

Try using the volatile keyword with the variable
Ref page: http://wiki.osdev.org/Printing_To_Screen
// note this example will always write to the top
// line of the screen
void write_string( int colour, const char *string )
{
volatile char *video = (volatile char*)0xB8000;
while( *string != 0 )
{
*video++ = *string++;
*video++ = colour;
}
}

For some reason, if I use char str[] = "blabla"; instead of char *str = "blabla"; it works.

First, have you set the SP before jumping Kernel or before running the function? If you have not, please set them appropriately. In your starting function you should set the stack pointer DS, SS; you can use inline assembly at the beginning of the program. Also instead char * p = "Something" you should use char var [] = "Something", or
char var[10];
var[1] = 'S';
var[2] = 'o';
or
char var[] = { 'S', 'o', 'm', 'e', ..., '\0' } ;
My bootloader establishes the GDT and makes the switcthing to 32 bit mode and jumps (jmp 0x8:0x8000) Here 0x8 is my Code segment address in GDT, 0x10 for the DS, SS; so it jumps to kernel. Before I hadn't set the SS, SP, DS and I could not get it printed so I have written this small code:
[bits 32]
MOV AX, 0x10 ; 0x10 points at the new data selector
MOV DS, eax
MOV ES, AX
MOV FS, AX
MOV GS, AX
MOV SS, AX
MOV eax, 0x200000
MOV esp, eax
and compiled it with nasm and added to beginning of the kernel program manually by using a HEX editor program.

Related

Iterating over string returns empty in c (os development)

I was making an os, or atleast trying to, but I stumbled upon a problem. While trying to iterate over a string to convert to char to print to screen, the returned char seemed to be empty!(I am actually new to os development); Here is the code snippet:
int offset = 0;
void clear_screen() {
unsigned char * video = 0xB8000;
for(int i = 0; i < 2000; i+=2){
video[i] = ' ';
}
}
void printc(char c) {
unsigned char * video = 0xB8000;
video[offset] = c;
video[offset+1] = 0x03;
offset += 2;
}
void print(unsigned char *string) {
char * sus = '\0';
uint32 i = 0;
printc('|');
sus[0] = 'a';
printc(sus[0]); //this prints "a" correctly
string[i] = 'c';
while (string[i] != '\0') {
printc(string[i]); //this while loop is only called once
i++; //it prints " " only once and exits
}
printc('|');
}
int bootup(void)
{
clear_screen();
// printc('h');
// printc('e');
// printc('l'); /* These work */
// printc('l');
// printc('o');
print("hello"); //this doesn't
return 1;
}
Output that it prints:
|a |
Thanks in advance!!
edit
New print function
void print(unsigned char *string) {
uint32 i = 0;
printc('|');
while (string[i] != '\0') {
printc('i'); //not printed
printc(string[i]);
i++;
}
printc('|');
}
still does not work
edit 2
updated the code as per #lundin's advice
int offset = 0;
void clear_screen() {
unsigned char * video = (unsigned char *)0xB8000;
for(int i = 0; i < 2000; i+=2){
video[i] = ' ';
}
}
void printc(char c) {
unsigned char * video = (unsigned char *)0xB8000;
video[offset] = c;
video[offset+1] = 0x03;
offset += 2;
}
void print(const char *string) {
int i = 0;
printc('|');
while (string[i] != '\0') {
printc('i');
printc(string[i]);
i++;
}
printc('|');
}
int bootup(void)
{
clear_screen();
// printc('h');
// printc('e');
// printc('l');
// printc('l');
// printc('o');
print("hello");
return 1;
}
stack:
init_lm:
mov ax, 0x10
mov fs, ax ;other segments are ignored
mov gs, ax
mov rbp, 0x90000 ;set up stack
mov rsp, rbp
;Load kernel from disk
xor ebx, ebx ;upper 2 bytes above bh in ebx is for cylinder = 0x0
mov bl, 0x2 ;read from 2nd sectors
mov bh, 0x0 ;head
mov ch, 1 ;read 1 sector
mov rdi, KERNEL_ADDRESS
call ata_chs_read
jmp KERNEL_ADDRESS
jmp $
Before proceeding I would recommend reading the OSDev wiki's page on text-based UIs.
While this may go beyond the scope of the question somewhat, I would strongly recommend that, rather than working with the character/attribute values as unsigned char manually, you might want to declare a struct type for those pairs:
struct TextCell {
volatile unsigned char ch;
volatile uint8_t attribute;
};
(You could actually be even more refined about it, by using a bitfield for the individual foreground, background, and decoration components of the attributes, but that's probably getting ahead of things.)
From there you can define the text buffer as a constant pointer:
const struct TextCell* text_buffer = (TextCell *)0xB8000;
You could further define
const uint16_t MAXH = 80, MAXV = 25;
uint16_t currv = 0, currh = 0;
struct TextCell* text_cursor = text_buffer;
void advance_cursor() {
text_cursor++;
if (currh < MAXH) {
currh++;
}
else {
currh = 0;
if (currv < MAXV) {
currv++;
}
else {
/* handle scrolling */
}
}
}
void gotoxy(uint16_t x, uint16_t y) {
uint16_t new_pos = x * y;
if (new_pos > (MAXV * MAXH)) {
text_cursor = text_buffer + (MAXV * MAXH);
currh = MAXH;
currv = MAXV;
}
else {
text_cursor += new_pos;
currh = x;
currv = y;
}
Which would lead to the following modifications of your code:
void kprintc(char c, uint8_t attrib) {
text_cursor->ch = c;
text_cursor->attribute = attrib;
advance_cursor();
}
void kprint(const char *string, uint8_t attribs) {
int i;
for (i = 0; string[i] != '\0'; i++) {
kprintc(string[i], attribs);
}
}
void clear_screen() {
for(int i = 0; i < (MAXH * MAXV); i++) {
kprintc(' ', 0);
}
}
int bootup(void) {
clear_screen();
// kprintc('h', 0x03);
// kprintc('e', 0x03);
// kprintc('l', 0x03);
// kprintc('l', 0x03);
// kprintc('o', 0x03);
kprint("hello", 0x03);
return 1;
}
So, why am I suggesting all of this extra stuff? Because it is a lot easier to debug this way, mainly - it divides the concerns up better, and structures the data (or in this case, the video text buffer) more effectively. Also, you'll eventually need to do something like this at some point in the project, so if it helps now, you might as well do it now.
If I am out of line in this, please let me know.
Your program has undefined behavior since it contains multiple lines that aren't valid C. You will have gotten compiler messages about those lines.
unsigned char * video = 0xB8000; etc is not valid C, you need an explicit cast. "Pointer from integer/integer from pointer without a cast" issues
Similarly, char * sus = '\0'; is also not valid C. You are trying to assign a pointer to a single character, which doesn't make sense. String handling beginner FAQ here: Common string handling pitfalls in C programming. It also addresses memory allocation basics.
sus[0] = 'a'; etc here you have wildly undefined behavior since sus isn't pointing at valid memory.
In case you are actually trying to access physical memory addresses, this isn't the correct way to do so. You need volatile qualified pointers. See How to access a hardware register from firmware? (In your case it probably isn't a register but everything from that link still applies - how to use hex constants etc.)
EDIT: void print(unsigned char *string) ... string[i] = 'c'; is also wrong. First of all you are passing a char* which is not necessarily compatible with unsigned char*. Then you shouldn't modify the passed string from inside a function called print, that doesn't make sense. This should have been const char* string to prevent such bugs. As it stands you are passing a string literal to this function and then try to modify it - that is undefined behavior since string literals are read-only.
Assuming gcc or clang, if you wish to block the compiler from generating an executable out of invalid C code, check out What compiler options are recommended for beginners learning C? In your case you also likely need the -ffreestanding option mentioned there.
char * sus = '\0';
Have not checked more... but this assigns a null pointer to sus, and most probably is not what you want to do.

Understanding hook_finder

I'm Trying to understand the PE Format & the source code of "hook_finder" in here
"https://github.com/Mr-Un1k0d3r/EDRs/blob/main/hook_finder64.c"
in this snippet I now it's trying to calculate Export_Table offset:
VOID DumpListOfExport(VOID *lib, BOOL bNt) {
DWORD dwIter = 0;
CHAR* base = (CHAR*)lib;
CHAR* PE = base + (unsigned char)*(base + 0x3c);
DWORD ExportDirectoryOffset = *((DWORD*)PE + (0x8a / 4));
CHAR* ExportDirectory = base + ExportDirectoryOffset;
DWORD dwFunctionsCount = *((DWORD*)ExportDirectory + (0x14 / 4));
DWORD OffsetNamesTableOffset = *((DWORD*)ExportDirectory + (0x20 / 4));
CHAR* OffsetNamesTable = base + OffsetNamesTableOffset;
printf("------------------------------------------\nBASE\t\t\t0x%p\t%s\nPE\t\t\t0x%p\t%s\nExportTableOffset\t0x%p\nOffsetNameTable\t\t0x%p\nFunctions Count\t\t0x%x (%d)\n------------------------------------------\n",
base, base, PE, PE, ExportDirectory, OffsetNamesTable, dwFunctionsCount, dwFunctionsCount);
for(dwIter; dwIter < dwFunctionsCount - 1; dwIter++) {
DWORD64 offset = *((DWORD*)OffsetNamesTable + dwIter);
CHAR* current = base + offset;
GetBytesByName((HANDLE)lib, current, bNt);
}
}
ox3c is e_lfnew offset. However, can't understand what's other hex values and why it's divided by 4 byte?
Further,
VOID GetBytesByName(HANDLE hDll, CHAR *name, BOOL bNt) {
FARPROC ptr = GetProcAddress((HMODULE)hDll, name);
DWORD* opcode = (DWORD*)*ptr;
if(bNt) {
if(name[0] != 'N' && name[1] != 't') {
return;
}
}
if((*opcode << 24) >> 24 == 0xe9) {
if(!IsFalsePositive(name)) {
printf("%s is hooked\n", name);
}
}
}
what's been exactly left & right shifting and Why 24 specifically?
From my understanding of EDRs, it adds a JMP instruction at the very beginning of the function and that's why the condition is trying to check if it's (0xe9), but how does it follow and be certain about the function flow?
and is this applicable only for ntdll.dll?
Sorry I'm starting to study the PE behavior and trying to make things very clear.
Thank you in advance
The function DumpListOfExport assumes that NtHeaders start at the offset 0x3c from the base but, this is not always the case depending on the size of the DOS stub. Probably, this code makes that assumption for ntdll.dll.
And in the function GetBytesByName, if first byte of the procedure starts with a JMP(in that case, it is near, relative jmp whose opcode starts with "E9") instruction and the procedure name is not in the false positives list, then the function makes decision that the function is hooked.
Let be the value of the 4-bytes pointed to by opcode 0xca0e4be9, left shifting it by 24 will result in 0xe9000000, and then right shifting by 24 the result will be 0x000000e9 which is the value of the first byte at ptr.
That procedure can be simplified as follows.
VOID GetBytesByName(HANDLE hDll, CHAR *name, BOOL bNt) {
FARPROC ptr = GetProcAddress((HMODULE)hDll, name);
BYTE* opcode = (BYTE*)ptr;
if(bNt) {
if(name[0] != 'N' && name[1] != 't') {
return;
}
}
if(!IsFalsePositive(name) && *opcode == 0xe9) {
printf("%s is hooked\n", name);
}
}
As a note : I can say that the code isn't written well, and doesn't follow any good coding style.

Why can't i exit from shellcode with a syscall?

I try to make a Programm where you put in some assembled assembly in hex and run it.
With simple instructions like int3 it works, but when I try to exit from the programm with a syscall it doesnt work.
I assembled it with rasm2
mov eax, 1
mov ebx, 12
int 0x80
and then put it as an argument ./Programm b801000000bb0c000000cd80 1
but i get a segfault.
Here is my code:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
char *base16dec(char *b16str) {
size_t stingrlength = strlen(b16str);
char *decodedstr = malloc(stingrlength / 2);
for (size_t i = 0; i < stingrlength; i += 2) {
u_int8_t num = 0;
char stringIn[3];
stringIn[0] = b16str[i];
stringIn[1] = b16str[i+1];
stringIn[2] = 0;
sscanf(stringIn, "%hhx", &num);
decodedstr[i/2] = (char) num;
}
return decodedstr;
}
this decodes the hex string
int main(int argc, char *argv[]) {
char *dirstr = "XXXXXX";
char dir[7];
strcpy(dir, dirstr);
int fd = mkstemp(dir);
if (fd == -1) {
dirstr = "/tmp/XXXXXX";
char dir[12];
strcpy(dir, dirstr);
fd = mkstemp(dir);
}
unlink(dir);
this creates the tmp file where the assembly is stored
char *stringIn;
if (argc == 2) {
stringIn = malloc(strlen(argv[1]));
strcpy(stringIn, argv[1]);
} else if (argc == 3) {
u_int8_t num = 0;
sscanf(argv[2], "%hhu", &num);
if (num == 1) {
char *done = base16dec(argv[1]);
stringIn = malloc(strlen(done));
strcpy(stringIn, done);
} else {
stringIn = malloc(strlen(argv[1]));
strcpy(stringIn, argv[1]);
}
} else {
stringIn = malloc(1024);
scanf("%s", stringIn);
char *done = base16dec(stringIn);
stringIn = malloc(strlen(done));
strcpy(stringIn, done);
}
this parses and copies the input to stringIn
ftruncate(fd, strlen(stringIn));
u_int8_t *code = mmap(NULL, strlen(stringIn), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE , fd, 0);
this expands the tmp file and makes it executable and creates a pointer to it named code
for (int i = 0; i < 1024; i++) {
code[i] = (u_int8_t) stringIn[i];
}
this copies the assembly bytes into code
#if __x86_64__
__asm__(
"mov %0, %%rbx\n"
"jmp *%%rbx"
:
: "g" (code)
: "memory"
);
#elif __i386__
__asm__(
"mov %0, %%ebx\n"
"jmp *%%ebx"
:
: "r" (code)
);
#else
#endif
this jumps to the the assembly
return 0;
}
EDIT:
I can't debug the shellcode using gdb
I use 64bit Linux Mint
I tried to copy 0 using strcpy
Since this is a shellcode you can't have null bytes. In your code you have 2 movs with immediates that are padded to 32-bits
mov eax, 1
mov ebx, 12
Which encodes as B801000000BB0C000000, when C hits the null bytes it thinks the string has ended so it only ends up copying part of the instruction and then it executes garbage.
Instead you'll need to use:
xor eax, eax
inc eax
xor ebx, ebx
mov bl, 12
This will provide the values you want for your system call and does not encode as any null bytes.

Segmentation fault with memmem()

I am attempting to find the size in bytes of some layers in a .gcode file for 3D printers. However, there is an error that I am getting from running a function to find the distance between two instances of the string ";LAYER:*". Here is my function source:
char* storeLayers(FILE* fp, int count) {
double size = get_filesize(fp);
uint8_t* file = (uint8_t*)malloc(size);
if(!file) {
printf("Error allocating 0x%lX bytes for GCode file\n",size);
fclose(fp);
return NULL;
}
int layerLen[] = {0};
fread(file,1,size,fp);
char* layerstr = NULL;
char* layer = ";LAYER:";
char layernum[100];
char* pointerlayernum;
uint8_t* layerfind;
uint8_t* lastLayerfind = 0;
uint8_t* tmpfind;
for(int i = 0; i <= count; i++) {
sprintf(layernum,"%d",i);
pointerlayernum = layernum;
// make count string
layerstr = addVars(layer,pointerlayernum);
printf("|%s|\n",layerstr);
layerfind = memmem(file,size,layerstr,strlen(layerstr);
if(!layerfind) {
printf("Unable to find %s in the file\n",layerstr);
return NULL;
}
printf("Found \"%s\" at 0x%08lX\n",layerstr,layerfind - file);
if(lastLayerfind != 0) {
tmpfind = (uint8_t*)(layerfind - file);
layerLen[i] = tmpfind - lastLayerfind;
printf("Length of layer block: 0x%X bytes\n",layerLen[i]);
}
lastLayerfind = (uint8_t*)(layerfind - file);
}
return "blah";
}
The addVars() function is as follows:
char* addVars(char *s1, char *s2) {
char *result = malloc(strlen(s1)+strlen(s2)+1);
strcpy(result, s1);
strcat(result, s2);
return result;
}
This error seems to only occur when I attempt to process more than 2 layers in int count. This is normal program output:
MacBook-Pro-27:fchost dayt0n$ ./fchost -d /Users/dayt0n/Downloads/paper_bin.gcode
Layers: 509
Filament Length: 4392.00 mm
|;LAYER:0|
Found ";LAYER:0" at 0x0000035F
|;LAYER:1|
Found ";LAYER:1" at 0x00002E67
Length of layer block: 0x2B08 bytes
|;LAYER:2|
Segmentation fault: 11
My GDB is broken for some odd reason, so I am using lldb and this is what lldb tells me:
MacBook-Pro-27:fchost dayt0n$ lldb fchost
(lldb) target create "fchost"
Current executable set to 'fchost' (x86_64).
(lldb) r -d /Users/dayt0n/Downloads/paper_bin.gcode /d
Process 21523 launched: '/Users/dayt0n/Github/fchost/fchost' (x86_64)
Layers: 509
Filament Length: 4392.00 mm
|;LAYER:0|
Found ";LAYER:0" at 0x0000035F
|;LAYER:1|
Found ";LAYER:1" at 0x00002E67
Length of layer block: 0x2B08 bytes
|;LAYER:2|
Process 21523 stopped
* thread #1: tid = 0xf706b, 0x00007fffeaa8338b libsystem_c.dylib`memmem + 104, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x100093000)
frame #0: 0x00007fffeaa8338b libsystem_c.dylib`memmem + 104
libsystem_c.dylib`memmem:
-> 0x7fffeaa8338b <+104>: movzbl (%rbx), %eax
0x7fffeaa8338e <+107>: cmpl %r13d, %eax
0x7fffeaa83391 <+110>: jne 0x7fffeaa833a5 ; <+130>
0x7fffeaa83393 <+112>: movq %rbx, %rdi
(lldb)
So, according to lldb, I know that the problem seems to reside within accessing memmem. Any help would be greatly appreciated.
I'd be looking at the int layerLen[] = {0};, for(int i = 0; i <= count; i++) {, layerLen[i] = tmpfind - lastLayerfind; sequence. The definition only allows for one int so, depending on the value of count, this may cause problems.
– paxdiablo

Handing a pointer over to another function in C

I'm having trouble with this code. When I execute "PrepareEncryption" (in example), the code returns a valid pointer, but when I pass it on to "EncryptBig" it isn't valid no more (points to random numbers). My best bet is that the original struct is deleted. So how do I preserve it, if that's the problem? And I know that there is a memory leak btw.
struct filecrypt
{
FILE* bestand;
FILE* nieuwbstnd;
unsigned int positie;
unsigned int size;
unsigned int huidig;
float procentum;
};
struct filecrypt *PrepareEncryption(char* locatie)
{
struct stat file_status;
struct filecrypt origineel, *mirror;
int error;
char* nieuw;
if (stat(locatie, &file_status) != 0)
return NULL;
error = fopen_s(&origineel.bestand, locatie, "rb");
if (error != 0)
return NULL;
error = strlen(locatie)+5;
nieuw = (char*)malloc(error);
if (nieuw == NULL)
return NULL;
strcpy_s(nieuw, error-3, locatie);
strcat_s(nieuw, error, ".cpt");
error = fopen_s(&origineel.nieuwbstnd, nieuw, "wb+");
if (error != 0)
return NULL;
origineel.huidig = 0;
origineel.positie = 0;
origineel.procentum = 0.0f;
origineel.size = file_status.st_size;
mirror = &origineel;
return mirror;
}
float EncryptBig(struct filecrypt *handle)
{
int i, index = 0;
float calc;
char buf, *bytes = (char*)malloc(10485760); // 10 MB
if (bytes == NULL)
{
handle = NULL;
fcloseall();
return -1.0f;
}
for (i = handle->huidig; i < (handle->huidig+10485760); i++)
{
if (i > handle->size)
break;
fseek(handle->bestand, i, SEEK_SET);
fread_s(&buf, 1, 1, 1, handle->bestand);
__asm
{
mov eax, dword ptr [bytes]
add eax, dword ptr [index]
mov cl, byte ptr [buf]
xor cl, 18
xor cl, 75
not cl
mov byte ptr [eax], cl
mov eax, dword ptr [index]
add eax, 1
mov dword ptr [index], eax
}
}
fwrite(bytes, 1, i, handle->nieuwbstnd);
fseek(handle->nieuwbstnd, i, SEEK_SET);
handle->huidig += i;
calc = (float)handle->huidig;
calc /= (float)handle->size;
calc *= 100.0f;
if (calc == 100.0)
{
// GEHEUGEN LEK!
// MOET NOG BIJGEWERKT WORDEN!
fcloseall();
handle = NULL;
}
return calc;
}
void example(char* path)
{
float progress;
struct filecrypt* handle;
handle = PrepareEncryption(path);
do
{
progress = EncryptBig(handle);
printf_s("%f", progress);
}
while (handle != NULL);
}
It's because you return a pointer to a local variable.
Local variables are stored on the stack, and when a function returns that area of the stack is reused by other functions, and you are left with a pointer that now points to unused memory or memory now occupied by something else. This is undefined behaviour, and might sometimes work, might sometimes give you "garbage" data, and may sometimes crash.
In PrepareEncryption you are returning pointer to struct filecrypt origineel, which is allocated on stack (local object). This is the problem. Just after the function returns (ends its execution) the memory occupied by origineel becomes invalid. You need to allocate it on the heap, by a call to malloc.
You do:
mirror = &origineel;
return mirror;
origineel is a local variable. The above is equivalent to:
return &origineel;
...you're returning a pointer to a local variable, that goes out of scope at the end of the function. The fact that it appears to sometimes return a valid pointer is just chance.
Use malloc, or better yet, pass the pointer address to the target location as an argument to your function and don't return it:
int *PrepareEncryption(struct filecrypt *origineel, char* locatie);
struct filecrypt myStruct;
PrepareEncryption(&myStruct, "abc");

Resources