Very brave of you to examine the source code
I noticed that SB does not have MKL() and similar functions though these are mentioned as planned in the manual. You will have to construct binary encodings using asc() / chr().
The only thing you can't do in SB is direct execution in memory.
asm = """
mov ecx,[p] 'ADDRESS OF CODE
cmp dword ptr [ecx],&h00905A4D 'DOS `MZ` SIGNATURE: `MZ` 90 00
jnz npef 'SKIP IF NOT PE
add ecx,&hff0 'MOVE o2 ENTRY POINT
npef: '
mov ebx,[psysfuns] 'BASE ADDRESS OF RUNTIME FUNCTION TABLE
call ecx 'CALL CODE
mov [function],eax 'RETURN DATA
"""
npef: '
mov ebx,[""" & psysfuns & """] 'BASE ADDRESS OF RUNTIME FUNCTION TABLE
call ecx 'CALL CODE
I noticed that SB does not have MKL() and similar functions though these are mentioned as planned in the manual. You will have to construct binary encodings using asc() / chr().
INCLUDE t.bas
a = 1
b = 1.0
sl_a = t::ArrayToString(a)
sr_b = t::ArrayToString(b)
PRINT HTA(sl_a),"\n"
PRINT HTA(sr_b),"\n"
END
FUNCTION HTA(arg)
FOR x = 1 TO LEN(arg)
z &= HEX(ASC(MID(arg,x,1)))
NEXT
HTA = z
END FUNCTION
Hi John,
Apart from these there is the more complex task of building an ELF header to replace the PE header. o2hdrs.bas deals with this aspect. I need to study some real ELF headers to get a clear picture of how they are used. But it promises to be a lot cleaner than PE.
And in conjunction with this, resource building will also be totally different. An area I have not researched yet.
Charles
This is how I would implement print in Oxygen's Linux run-time library:
There are more than those Charles if you start think about the windows, console and other api calls.
Well certainly John, If Linux is that simple!
o2link is the first one to go for.
`MZ` 90 00
03 00 00 00
04 00 00 00
FF FF 00 00
B8 00 00 00
00 00 00 00
40 00 00 00
$20
hle8
0E 1F BA 0E
00 B4 09 CD
21 B8 01 4C
CD 21
`This program cannot be run in DOS mode.` 0d 0a 00
/e8
`PE` 00 00
hw014c
hw0005
hl4E331D62
hl0
hl0
hw00e0
hw0102
hw010b 'MAGIC
02
00
hl0
hl0
hl00005000
ga _main_
ga _code_
ga base_of_data
hg00400000
hl1000
hl200
hw4
hw0
hw1
hw0
hw4
hw0
hl0
hl5000
hl400
hl0
hw2
hw0
hg00100000
hg00001000
hg00100000
hg00001000
hl0
hl10
hl0 hl0
ga imports hl200
ga resources hl0
$68
`.text` 00 00 00 hl00000000 ga _code_ hl0000 $10 hl60000020
`.data` 00 00 00 hl40000000 ga _data hl0200 $10 hlc0000040
`.bss` 00 00 00 00 hl00005000 ga bssdata hl0000 $10 hlc0000080
`.idata` 00 00 hl02000000 ga imports hl0200 $10 hlc0000040
`.rsrc` 00 00 00 hl02000000 ga resources hl0200 $10 hl40000040
/0ff0 e9 gf _o2_
/+1000
'
._code_ ' ._code_
._main_ ' ._main_
E8 gl get_bss ' call get_bss
8B F8 ' mov edi,eax
E8 gl get_iat ' call get_iat
8B D8 ' mov ebx,eax
89 9F 58 02 00 00 ' mov [edi+600],ebx
6A 00 ' push 0
FF 53 0C ' call [ebx+12]
89 87 60 02 00 00 ' mov [edi+608],eax
9b db e3 ' finit
E8 gf get_oxygen ' call fwd get_oxygen
83 F8 00 ' cmp eax,0
0F 84 gf nend ' jz fwd nend
FF D0 ' call eax
8B D8 ' mov ebx,eax
E8 gf _o2_ ' call fwd _o2_
E8 gl get_bss ' call get_bss
8B F8 ' mov edi,eax
8B 9F 58 02 00 00 ' mov ebx,[edi+600]
8B 87 68 02 00 00 ' mov eax,[edi+616]
83 F8 00 ' cmp eax,0
0F 84 gf noxyfree ' jz fwd noxyfree
50 ' push eax
FF 53 08 ' call [ebx+8]
.noxyfree ' .noxyfree
.nend ' .nend
6A 00 ' push 0
8B C4 ' mov eax,esp
50 ' push eax
FF B7 60 02 00 00 ' push [edi+608]
FF 53 14 ' call [ebx+20]
FF 53 18 ' call [ebx+24]
.get_iat ' .get_iat
E8 gf here ' call fwd here
.here ' .here
58 ' pop eax
81 E8 ga here ' sub eax,here
81 C0 ga import_address_table ' add eax,import_address_table
C3 ' ret
.get_bss ' .get_bss
E8 gf here ' call fwd here
.here ' .here
58 ' pop eax
81 E8 ga here ' sub eax,here
81 C0 ga bssdata ' add eax,bssdata
C3 ' ret
.get_oxygen ' .get_oxygen
57 ' push edi
68 66 67 00 00 ' push 0x00006766
68 65 6E 2E 63 ' push 0x632e6e65
68 6F 78 79 67 ' push 0x6779786f
8B C4 ' mov eax,esp
6A 00 ' push 0
68 80 00 00 00 ' push 128
6A 03 ' push 3
6A 00 ' push 0
6A 01 ' push 1
68 00 00 00 80 ' push 0x80000000
50 ' push eax
FF 53 1C ' call [ebx+28]
83 C4 0C ' add esp,12
83 F8 00 ' cmp eax,0
0F 84 gf nconfig ' jz fwd nconfig
8B F0 ' mov esi,eax
81 EC 04 08 00 00 ' sub esp,2052
8B FC ' mov edi,esp
C7 07 00 00 00 00 ' mov [edi],0
6A 00 ' push 0
8B C4 ' mov eax,esp
6A 00 ' push 0
50 ' push eax
68 00 08 00 00 ' push 2048
57 ' push edi
56 ' push esi
FF 53 20 ' call [ebx+32]
56 ' push esi
FF 53 24 ' call [ebx+36]
8B CF ' mov ecx,edi
FF C9 ' dec ecx
( ' (
FF C1 ' inc ecx
8A 01 ' mov al,[ecx]
80 F8 20 ' cmp al,32
0F 87 rl ' ja repeat
) ' )
C7 01 00 00 00 00 ' mov [ecx],0
57 ' push edi
FF 13 ' call [ebx]
81 C4 08 08 00 00 ' add esp,2056
83 F8 00 ' cmp eax,0
0F 85 gf ndll ' jnz fwd ndll
.nconfig ' .nconfig
68 6C 6C 00 00 ' push 0x00006c6c
68 65 6E 2E 64 ' push 0x642e6e65
68 6F 78 79 67 ' push 0x6779786f
8B C4 ' mov eax,esp
50 ' push eax
FF 13 ' call [ebx]
83 C4 0C ' add esp,12
83 F8 00 ' cmp eax,0
0F 85 gf ndll ' jnz fwd ndll
60 ' pushad
83 EC 20 ' sub esp,32
8B CC ' mov ecx,esp
C7 01 4F 32 00 00 ' mov [ecx],0x324f
C7 41 04 6F 78 79 67 ' mov [ecx+4],0x6779786f
C7 41 08 65 6E 2E 64 ' mov [ecx+8],0x642e6e65
C7 41 0C 6C 6C 3F 00 ' mov [ecx+12],0x003f6c6c
6A 00 ' push 0
51 ' push ecx
83 C1 04 ' add ecx,4
51 ' push ecx
6A 00 ' push 0
FF 53 2C ' call [ebx+44]
83 C4 20 ' add esp,32
61 ' popad
5F ' pop edi
C3 ' ret
.ndll ' .ndll
5F ' pop edi
89 87 68 02 00 00 ' mov [edi+616],eax
8B D0 ' mov edx,eax
83 EC 10 ' sub esp,16
8B C4 ' mov eax,esp
C7 00 6F 32 5F 6C ' mov [eax],0x6c5f326f
C7 40 04 69 62 00 00 ' mov [eax+4],0x00006269
50 ' push eax
52 ' push edx
FF 53 04 ' call [ebx+04]
83 C4 10 ' add esp,16
C3 ' ret
._o2_ ' ._o2_
E9 gf _main ' jmp fwd _main
._mem ' ._mem
E8 gl get_bss ' call get_bss
8B D8 ' mov ebx,eax
C3 ' ret
._newbuf ' ._newbuf
68 00 10 00 00 ' push 4096
6A 00 ' push 0
FF 93 A0 00 00 00 ' call [ebx+160]
C7 C1 00 10 00 00 ' mov ecx,4096
8B D0 ' mov edx,eax
( ' (
C7 02 00 00 00 00 ' mov [edx],0
83 C2 04 ' add edx,4
83 E9 04 ' sub ecx,4
0F 8F rl ' jg repeat
) ' )
89 07 ' mov [edi],eax
83 C7 08 ' add edi,8
C3 ' ret
._main ' ._main
55 ' push ebp
8B EC ' mov ebp,esp
53 ' push ebx
56 ' push esi
57 ' push edi
8B FB ' mov edi,ebx
E8 gl get_bss ' call get_bss
8B D8 ' mov ebx,eax
8B F0 ' mov esi,eax
C7 C1 64 00 00 00 ' mov ecx,100
( ' (
8B 07 ' mov eax,[edi]
89 06 ' mov [esi],eax
83 C7 04 ' add edi,4
83 C6 04 ' add esi,4
FF C9 ' dec ecx
0F 8F rl ' jg repeat
) ' )
81 C7 6C 06 00 00 ' add edi,1644
81 C6 6C 06 00 00 ' add esi, 1644
C7 C1 00 02 00 00 ' mov ecx,512
( ' (
8B 07 ' mov eax,[edi]
89 06 ' mov [esi],eax
83 C7 04 ' add edi,4
83 C6 04 ' add esi,4
FF C9 ' dec ecx
0F 8F rl ' jg repeat
) ' )
8D BB 80 02 00 00 ' lea edi,[ebx+640]
E8 gl _newbuf ' call _newbuf
E8 gl _newbuf ' call _newbuf
E8 gl _newbuf ' call _newbuf
E8 gl _newbuf ' call _newbuf
8D BB A8 02 00 00 ' lea edi,[ebx+680]
E8 gl _newbuf ' call _newbuf
' '_1
8D 83 gc 1 '
FF 93 68 08 00 00 ' call [ebx+2152]
C6 C2 01 ' mov dl,1
FF 93 80 08 00 00 ' call [ebx+2176]
C6 C2 01 ' mov dl,1
33 C0 ' xor eax,eax
FF 93 88 08 00 00 ' call [ebx+2184]
50 ' push eax
C7 C0 01 00 00 00 ' mov eax,1
FF 93 B0 08 00 00 ' call [ebx+2224]
58 ' pop eax
FF 93 B0 08 00 00 ' call [ebx+2224]
50 ' push eax
C6 C2 01 ' mov dl,1
FF 93 C0 09 00 00 ' call [ebx+2496]
FF 93 38 08 00 00 ' call [ebx+2104]
' '_2
50 ' push eax
FF 93 90 09 00 00 ' call [ebx+2448]
FF 93 60 08 00 00 ' call [ebx+2144]
58 ' pop eax
._end_ ' ._end_
5F ' pop edi
5E ' pop esi
5B ' pop ebx
8B E5 ' mov esp,ebp
5D ' pop ebp
C3 ' ret
._error_ ' ._error_
51 ' push ecx
FF 93 00 08 00 00 ' call [ebx+2048]
E9 gl _end_ ' jmp _end_
.get_bss ' .get_bss
E8 gf here ' call fwd here
.here ' .here
58 ' pop eax
81 E8 ga here ' sub eax,here
81 C0 ga bssdata ' add eax,bssdata
C3 ' ret
01 `end_of_code` 01 /+1000 '
.base_of_data
._data
gd 1 "Hello World!" 00 00
00 01 `end_of_data` 01 /+1000
.bssdata
$5000
.imports
ga name_list1 hl0 hl0 ga module_name1 ga address_list1
ga name_list3 hl0 hl0 ga module_name3 ga address_list3
hl0 hl0 hl0 hl0 hl0 ' termination
.module_name1 `KERNEL32.DLL` 00
.module_name3 `USER32.DLL` 00
.name_list1 gg _LoadLibrary gg _GetProcAddress gg _FreeLibrary
gg _GetModuleHandle gg _GetCommandLine gg _GetExitCodeProcess gg _ExitProcess
gg _CreateFile gg _ReadFile gg _CloseHandle hg0
.name_list3 gg _MessageBoxA gg _MessageBoxW hg0
/+8 .import_address_table
.address_list1 gg _LoadLibrary gg _GetProcAddress gg _FreeLibrary
gg _GetModuleHandle gg _GetCommandLine gg _GetExitCodeProcess gg _ExitProcess
gg _CreateFile gg _ReadFile gg _CloseHandle hg0
.address_list3 gg _MessageBoxA gg _MessageBoxW hg0
/+4 ._LoadLibrary hw0 `LoadLibraryA` 00
/+4 ._GetProcAddress hw0 `GetProcAddress` 00
/+4 ._FreeLibrary hw0 `FreeLibrary` 00
/+4 ._GetModuleHandle hw0 `GetModuleHandleA` 00
/+4 ._GetCommandLine hw0 `GetCommandLineA` 00
/+4 ._GetExitCodeProcess hw0 `GetExitCodeProcess` 00
/+4 ._ExitProcess hw0 `ExitProcess` 00
/+4 ._CreateFile hw0 `CreateFileA` 00
/+4 ._ReadFile hw0 `ReadFile` 00
/+4 ._CloseHandle hw0 `CloseHandle` 00
/+4 ._MessageBoxA hw0 `MessageBoxA` 00
/+4 ._MessageBoxW hw0 `MessageBoxW` 00
01 `end_of_imports` 01
/+1000
.resources
hl0 hl0 hl1 hw0 hw1
hl6 hl80000018
hl0 hl0 hl1 hw0 hw1
hl1 hl80000030
hl0 hl0 hl1 hw0 hw1
nl2057 hl48
ga data1 nl32 nl0 hl0
.data1 nw11 w`OxygenBasic` nw3 w`o2h` nw0
/+200
01 `end_of_resources` 01
/+1000
Oxygen can emit a machine script for the memory image but not for the PE file itself.Im not expert but i see that old LibryCompiler written in VB 6.0 can create directly PE file.
Here is a machine script for "Hello World!"
QuoteOxygen can emit a machine script for the memory image but not for the PE file itself.Im not expert but i see that old LibryCompiler written in VB 6.0 can create directly PE file.
Normally you never see it so it is quite a shock when all the opcodes and link information is made visible
The LibryCompiler has different files like assembler, linker etc. as well.
QuoteThe LibryCompiler has different files like assembler, linker etc. as well.
Where you see assembler in Libry source code ???
There is only pure machine hex code...
The best way to test the code initially would be to create a program for viewing the hexadecimal byte output.
The project aims to create a complete, portable, multi-architecture,
unix-like toolchain for reverse engineering.
It is composed by an hexadecimal editor (radare) with a wrapped
IO layer supporting multiple backends for local/remote files,
debugger (osx,bsd,linux,w32), stream analyzer, assembler/disassembler
(rasm) for x86,arm,ppc,m68k,java,msil,sparc code analysis modules and
scripting facilities. A bindiffer named radiff, base converter (rax),
shellcode development helper (rasc), a binary information extracter
supporting (pe, mach0, elf, class, ...) named rabin, and a block-based
hash utility called rahash.
This package contains the gtk enabled edition of radare.
jrs@laptop:~$ radare -h
radare [options] [file]
-s [offset] seek to the desired offset (cfg.seek)
-b [blocksize] change the block size (512) (cfg.bsize)
-i [script] interpret radare or ruby/python/perl/lua script
-p [project] load metadata from project file
-l [plugin.so] link against a plugin (.so or .dll)
-e [key=val] evaluates a configuration string
-d [program|pid] debug a program. same as --args in gdb
-f set block size to fit file size
-L list all available plugins
-w open file in read-write mode
-x dump block in hexa and exit
-n do not load ~/.radarerc and ./radarerc
-v same as -e cfg.verbose=false
-V show version information
-u unknown size (no seek limits)
-h this help message
jrs@laptop:~$ radare -L
haret Read WCE memory ( haret://host:port )
shm shared memory ( shm://key )
mmap memory mapped device ( mmap://file )
serial serial port access ( serial://path/to/dev:speed )
debug Debugs or attach to a process ( dbg://file or pid://PID )
malloc memory allocation ( malloc://size )
remote TCP IO ( listen://:port or connect://host:port )
winedbg Wine Debugger interface ( winedbg://program.exe )
windbg Windbg serial port debugger ( windbg:///path/to/socket )
socket socket stream access ( socket://host:port or socket://./socket.file )
gxemul GxEmul Debugger interface ( gxemul://program.arm )
bfdbg brainfuck debugger
gdbwrap Connect to remote GDB using eresi's gdbwrap (gdbwrap://host:port)
gdb Debugs/attach with gdb (gdb://file, gdb://PID, gdb://host:port)
gdbx GDB shell interface 'gdbx://program.exe args' )
posix plain posix file access
jrs@laptop:~$
jrs@laptop:~/.wine/drive_c/o2h/A36$ radare Oxygen.dll
open ro Oxygen.dll
Generating default ~/.radarerc...
> Importing file information...
[Information]
class=PE32
dll=True
machine=i386
big_endian=False
subsystem=Windows CUI
relocs=False
line_nums=True
local_syms=True
debug=True
number_of_sections=8
baddr=0x10000000
section_alignment=4096
file_alignment=512
image_size=6721536
[Entrypoint]
Memory address: 0x100010c0
> Importing symbols...
8 sections added
TODO
63 imports added
20 symbols added
4096 strings added
0
0
> Analyzing code...
strings: 2398
functions: 445
structs: 0
data_xrefs: 1199
code_xrefs: 1379
[0x100010C0]>
the assembler adds $58 to the code section (only valid for the intel processors).ooups i don't know that...
pr+=mid ("0"+hex(a),-2) " "
Quotethe assembler adds $58 to the code section (only valid for the intel processors).ooups i don't know that...
Anyway Libry is not bad example how write native compiler,right?
'TEST HEXADECIMAL TO BINARY CONVERSION IN SB
s="B8 04 03 02 01 c3"
le=len(s)
i=1
j=1
while i<le
w="0x"+mid(s,i,2)
print val(w) & " "
v[j]=chr(w)
i+=3
j+=1
wend
op=join("",v)
print " " & len(op) & " >> "
for i=1 to len(op)
print hex(asc(mid(op,i,1))) & " "
next
line input z
s = CHR(0xB8)&CHR(0x04)&CHR(0x03)&CHR(0x02)&CHR(0x01)&CHR(0xC3)
There is no internal difference between decimal and hexadecimal numbers for ScriptBasic. The lexical analyzer converts both format to internal representation and stores the value of the number. In other words wherever you are allowed to use a decimal number you are allowed to use a hexadecimal number or any radix number as well. You should decide whether to use decimal or hexadecimal or any other radix number for your convenience taking care of BASIC source code readability.
MODULE ASM
pop{"eax"} = CHR(0x58)
pop{"ebx"} = CHR(0x5B)
pop{"edi"} = CHR(0x5F)
pop{"esi"} = CHR(0x5E)
pop{"ebp"} = CHR(0x5D)
push{"eax"} = CHR(0x50)
push{"edi"} = CHR(0x57)
END MODULE
Do_Stuff = _
ASM::pop{"eax"} & _
ASM::push{"edi"} & _
ASM::pop{"edi"}
open "t.bin" for binary as 1
op=input(1000,1)
t_size = filelen("t.bin")
open "t.bin" for binary as 1
op=input(t_size,1)
Yes, I've been studying associative arrays. They are an elegant idea but quite expensive to process behind the scenes.
This is the definitive reference for x86 programming:
_mov = CHR(0x01)
_inc = CHR(0x05)
_dec = CHR(0x09)
_push = CHR(0x13)
_pop = CHR(0x18)
_add = CHR(0x22)
_sub = CHR(0x26)
_mul = CHR(0x30)
_div = CHR(0x34)
_cmp = CHR(0x38)
_and = CHR(0x42)
_or = CHR(0x46)
_xor = CHR(0x49)
_test = CHR(0x53)
_xchg = CHR(0x58)
_movsx = CHR(0x63)
_movzx = CHR(0x69)
jrs@laptop:~/sljit/bin$ ./sljit_test
Generating code for: x86-64
Executable allocator: ok
test1 ok
test2 ok
test3 ok
test4 ok
test5 ok
test6 ok
test7 ok
test8 ok
test9 ok
test10 ok
test11 ok
test12 ok
test13 ok
test14 ok
test15 ok
test16 ok
test17 ok
test18 ok
test19 ok
test20 ok
test21 ok
test22 ok
test23 ok
test24 ok
test25 ok
test26 ok
test27 ok
test28 ok
test29 ok
test30 ok
test31 ok
test32 ok
test33 ok
test34 ok
test35 ok
test36 ok
test37 ok
test38 ok
test39 ok
test40 ok
All tests are passed.
jrs@laptop:~/sljit/bin$
ASM[1]{"nam"} = "load"
ASM[1]{"mod"} = CHR(0x1)
ASM[1]{"dir"} = CHR(0x8b)
ASM[1]{"cdi"} = -1
ASM[1]{"imm"} = CHR(0xb8)
ASM[1]{"cim"} = -1
ASM[2]{"nam"} = "stor"
ASM[2]{"mod"} = CHR(0x1)
ASM[2]{"dir"} = CHR(0x89)
ASM[2]{"cdi"} = -1
ASM[2]{"imm"} = -1
ASM[2]{"cim"} = -1
ASM[3]{"nam"} = "+"
ASM[3]{"mod"} = CHR(0x2)
ASM[3]{"dir"} = CHR(0x03)
ASM[3]{"cdi"} = -1
ASM[3]{"imm"} = CHR(0x81)
ASM[3]{"cim"} = CHR(0x0)
ASM[4]{"nam"} = "-"
ASM[4]{"mod"} = CHR(0x2)
ASM[4]{"dir"} = CHR(0x2b)
ASM[4]{"cdi"} = -1
ASM[4]{"imm"} = CHR(0x81)
ASM[4]{"cim"} = CHR(0x5)
ASM[5]{"nam"} = "cmp"
ASM[5]{"mod"} = CHR(0x2)
ASM[5]{"dir"} = CHR(0x3b)
ASM[5]{"cdi"} = -1
ASM[5]{"imm"} = CHR(0x81)
ASM[5]{"cim"} = CHR(0x7)
ASM[6]{"nam"} = "*"
ASM[6]{"mod"} = CHR(0x3)
ASM[6]{"dir"} = CHR(0xf7)
ASM[6]{"cdi"} = CHR(0x05)
ASM[6]{"imm"} = -1
ASM[6]{"cim"} = -1
ASM[7]{"nam"} = "/"
ASM[7]{"mod"} = CHR(0x3)
ASM[7]{"dir"} = CHR(0xf7)
ASM[7]{"cdi"} = 0x05
ASM[7]{"imm"} = -1
ASM[7]{"cim"} = -1
ASM[8]{"nam"} = "and"
ASM[8]{"mod"} = CHR(0x4)
ASM[8]{"dir"} = CHR(0x23)
ASM[8]{"cdi"} = -1
ASM[8]{"imm"} = CHR(0x81)
ASM[8]{"cim"} = CHR(0x4)
nam="+"
vai=-1
van="a"
vav=123
function mklong(v)
h=right("0000000" & hex(v),8)
'print h
mklong=chr(asc(mid(h,7,1))*16+asc(mid(h,8,1))) & _
chr(asc(mid(h,5,1))*16+asc(mid(h,6,1))) & _
chr(asc(mid(h,3,1))*16+asc(mid(h,4,1))) & _
chr(asc(mid(h,1,1))*16+asc(mid(h,2,1)))
end function
if nam="+" then
'direct or immediate
if vai<>0 then
cod=chr(0x03) & chr(0x85) & mklong(vai*4)
else
cod=chr(0x81) & chr(0*8) & mklong(vav)
end if
elseif nam="-" then
'direct or immediate
if vai<>0 then
cod=chr(0x2b) & chr(0x85) & mklong(vai*4)
else
cod=chr(0x81) & chr(5*8) & mklong(vav)
end if
end if
print "ok"
line input a
Can I put comments on the same line as code?
I'm curious, do you know of a high level language that will translate assembly code (text) to it's binary executable format that the language can execute ? (bypassing the assembler part)