How to Call MAChine Code Stored in Char Array

How to call machine code stored in char array?

One first problem might be that the location where the prog data is stored is not executable.

On Linux at least, the resulting binary will place the contents of global variables in the "data" segment or here, which is not executable in most normal cases.

The second problem might be that the code you are invoking is invalid in some way. There's a certain procedure to calling a method in C, called the calling convention (you might be using the "cdecl" one, for example). It might not be enough for the called function to just "ret". It might also need to do some stack cleanup etc. otherwise the program will behave unexpectedly. This might prove an issue once you get past the first problem.

Executing machine code in an array in C. Is this executing an Integer?

What I'm wondering though is why calling ret(), which appears to be an integer assigned to the value (int(*)())code works

ret is not an integer, it is a pointer to a function returning an integer. The "inline" syntax, i.e. int (*ret)() is harder to "decipher" than an equivalent typedef, i.e.

typedef int (*func_returning_int)();
...
func_returning_int ret = (func_returning_int)code;

Note: It goes without saying that this is undefined behavior regardless of the way you go about casting pointers.

c++ how to run an .exe file whose contents are stored in a char array?

This shows how to Load an EXE File and Run It from Memory : http://www.codeproject.com/KB/cs/LoadExeIntoAssembly.aspx

Additional readings here : CreateProcess from memory buffer and here : How to run unmanaged executable from memory rather than disc

C function from assembler code as a char string

About the code example

Pasting the second answer's text from your link to a translator gave me:

And you can make it so that the machine code will be located in an array. Here's how you can write a program to count the number of characters in a string.

So it's only an example about how to use assembly code inside a C program. One could use __asm, but many don't like the syntax there. Therefore the assembly source code is first assembled externally (using NASM or FASM for example) and the resulting machine code is then embedded as a char array in the C program.

Make the code executable

As Peter Cordes already mentioned, it's mostly not possible to execute code within data sections (where this char array is stored in the program). There are two ways to execute the code anyway: Either the appropriate compiler settings have to be set (to make the data section executable) or additional memory has to be allocated that is executable.

Under Linux, for example, you can use mmap to request such storage and then copy the code over:

void* executableStorage = mmap(NULL, sizeof(executableCode),
PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_PRIVATE, 0, 0);
memcpy(executableStorage, executableCode, sizeof(executableCode));

Under Windows, something similar can be done with GlobalAlloc, for example, which always returns an executable memory area.

Random assembler

The first answer from the linked question is about the random numbers:

The simplest option is to implement a linear congruent generator:

R1 = (a * R0 + b) mod M

Here a and b are constant coefficients (are selected), M is the modulus, the maximum value for a pseudo-random number (the minimum will be 0), R0 is the result the previous call to the generator (for the first call, you can substitute any number).

Linear-feedback shift registers are another way to easily generate pseudo-random numbers.

Why does this opportunity exists?

It is not really a functionality of C. Since C is very close to hardware, everything can be interpreted as data, pointer or even as program code. By casting with a certain data type, you can switch between them. Therefore this possibility will probably also be described somewhere. Conversely, C-code could also be interpreted as data:

#include <stdio.h>

int main() {
// Interpret the main function (program code) as data
unsigned char* data = (unsigned char*) main;

// Print out some machine code of the main-function
for (int i=0; i<64; i++) {
printf("%02X ", data[i]);

if ((i & 15) == 15)
printf("\n");
}
}

So C offers these possibilities. Whether or not they are also allowed is not a matter for the language C. Security mechanisms, which are primarily provided by the operating system, can make memory areas and thus this data write-protected or non-executable.

Because of these security mechanisms, the way with the char array is no longer really practical. It was more of a quick-and-dirty solution, it's a bad programming style and impractical: every time the assembler code was changed, it would have to be manually transferred to the C program. Normally you would write the assembler code in a separate file and then link the assembled object file with the C object files:

   assembly                 object              executable
source code files program
assembler linker
ASSEMBLY.asm ────────────> ASSEMBLY.o ───┬───> ./PROGRAM

c-compiler │
PROGRAM.c ────────────> PROGRAM.o ───┘

c source code

What the memory difference between char *array and char array[]?

char tmp[] = "hello"; is an array of 6 characters initialized to "hello\0" (it has automatic storage duration and resides within the program stack).

char *tmp = "hello"; is a pointer to char initialized with the address for the string literal "hello\0" that resides in readonly memory (generally within the .rodata section of the executable, readonly on all but a few implementations).

When you have char tmp[] = "hello";, as stated above, on access the array is converted to a pointer to the first element of tmp. It has type char *. When you take the address of tmp (e.g. &tmp) it will resolve to the same address, but has a completely different type. It will be a pointer-to-array-of char[6]. The formal type is char (*)[6]. And since type controls pointer arithmetic, iterating with the different types will produce different offsets when you advance the pointer. Advancing tmp will advance to the next char. Advancing with the address of tmp will advance to the beginning of the next 6-character array.

When you have char *tmp = "hello"; you have a pointer to char. When you take the address, the result is pointer-to-pointer-to char. The formal type is char ** reflecting the two levels of indirection. Advancing tmp advances to the next char. Advancing with the address of tmp advances to the next pointer.

Reading from memory and getting in char array.. What if a char in that contains 1 byte that suppose to be a 1 byte length and length is a number

But in C number is int or long.

char is an integral type which can be used to represent numbers, the same as short, int or long.

It has a maximum value of CHAR_MAX.

One problem is that the signedness of char is implementation-defined. When in doubt, be explicit with signed char (SCHAR_MAX) or unsigned char (UCHAR_MAX).

Alternatively, use fixed width integer types to make it easier to reason about the byte width of the data you are working with.

The fields in the EPS table are denoted as being of size BYTE, WORD, and DWORD. These can be represented by uint8_t, uint16_t, and uint32_t respectively, as you almost certainly want unsigned integers.


This code

char x1[3];
memcpy(x1,&mem[4],2);
x1[2]='\0';
long v=strtol(x1,'\0',16);

printf("max size %lx\n",v);

that attempts to parse the Maximum Structure Size as if it were a number represented by two characters is incorrect. The Maximum Structure Size is a 16-bit integer.

mem=mem+length; does not make much sense, as this would place you in memory beyond the table. I am not sure what the two printf calls that follow are trying to print.

Additionally, your example includes some errant code (unused variables: i, y, j).

Everything else is more-or-less correct, if messy.


Below is a simple example that seemingly works on my machine, using the smbios_entry_point table file. You should be able to use it as reference to adjust your program accordingly.

$ uname -rmo
5.14.21-210.current x86_64 GNU/Linux
#include <fcntl.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define EPS_SIZE 31
#define TARGET_FILE "/sys/firmware/dmi/tables/smbios_entry_point"

void print_buffer(uint8_t *eps) {
printf("Anchor string: %c%c%c%c\n", eps[0], eps[1], eps[2], eps[3]);
printf("Checksum: %02Xh\n", eps[4]);
printf("Entry point length: %02Xh\n", eps[5]);
printf("Major version: %02Xh\n", eps[6]);
printf("Minor version: %02Xh\n", eps[7]);

uint16_t mss;
memcpy(&mss, eps + 8, sizeof mss);
printf("Maximum structure size: %" PRIu16 " bytes\n", mss);

printf("Entry point revision: %02Xh\n", eps[10]);
printf("Formatted area: %02Xh %02Xh %02Xh %02Xh %02Xh\n",
eps[11], eps[12], eps[13], eps[14], eps[15]);
printf("Intermediate anchor string: %c%c%c%c%c\n",
eps[16], eps[17], eps[18], eps[19], eps[20]);
printf("Intermediate checksum: %02Xh\n", eps[21]);

uint16_t stl;
memcpy(&stl, eps + 22, sizeof stl);
printf("Structure table length: %" PRIu16 " bytes \n", stl);

uint32_t sta;
memcpy(&sta, eps + 24, sizeof sta);
printf("Structure table address: 0x%08x\n", sta);

uint16_t nsmbs;
memcpy(&nsmbs, eps + 28, sizeof nsmbs);
printf("Number of SMBIOS structures: %" PRIu16 "\n", nsmbs);

printf("SMBIOS BCD revision: %02Xh %02Xh\n",
eps[30] >> 4, eps[30] & 0x0f);
}

int main(void) {
uint8_t buf[EPS_SIZE];
int fd = open(TARGET_FILE, O_RDONLY);

read(fd, buf, sizeof buf);
close(fd);

print_buffer(buf);
}

stdout:

Anchor string: _SM_
Checksum: C2h
Entry point length: 1Fh
Major version: 02h
Minor version: 07h
Maximum structure size: 184 bytes
Entry point revision: 00h
Formatted area: 00h 00h 00h 00h 00h
Intermediate anchor string: _DMI_
Intermediate checksum: DCh
Structure table length: 2229 bytes
Structure table address: 0x000ed490
Number of SMBIOS structures: 54
SMBIOS BCD revision: 02h 07h

You may also be interested in dmidecode and its source code.

Store an int in a char array?

Not the most optimal way, but is endian safe.


int har = 0x01010101;
char a[4];
a[0] = har & 0xff;
a[1] = (har>>8) & 0xff;
a[2] = (har>>16) & 0xff;
a[3] = (har>>24) & 0xff;

Store words in char array C language

Consider the following example:

#include <stdio.h>
#include <string.h>

#define MAXSTRLEN 20
#define MAXWORD 6

int main(void)
{
char arr[MAXWORD][MAXSTRLEN+1] = {0};
char str[] ="This is my text example";
char *pch;
int i = 0;
pch = strtok (str," ");
while (pch != NULL && i < MAXWORD)
{
strncpy(arr[i++], pch, MAXSTRLEN);
pch = strtok (NULL, " ");
}
return 0;
}


Related Topics



Leave a reply



Submit