executing from variable

Started by newdep, June 01, 2005, 01:12:03 PM

Previous topic - Next topic

newdep

Hi Lutz,



Do you know if its possible to execute from variable? Eighter in C or Newlisp.



example:



(setq a '(here is binary data stored ) )



I would love to be able to do an (exec a) but its not inside newlisp.



The concept is, reading a file into a newlisp list/variable to be able to

include the data inside the newlisp script source-code itself.

During execution of the newlisp script the data can be executed.  (by calling

to its variable or memory address) To prevent all files on being seperate

 files on disk and make 'linking newlisp more complete im thinking of this feature but i dont to have any solution yet...



Any hint is welcome..



Norman.
-- (define? (Cornflakes))

Lutz

#1
You could do it this way:

; call a function specified as binary data from newLISP
; ----- this is a wild unsupported hack!
; do not try this unless you know what you are doing!

; get a template cell for a library function
; from any library function

(set 'foo (import "libc.so" "kill"))

; get you binary data
; you could encode those with "0102" etc.
; specifying each byte as a 3-digit decimal
; or you could load it from a file

(set 'bindata "<you binary data goes here>")

; copy the address of the binary data into the contents
; field of the 'foo' function cell at offset 12

(cpymem (pack "ld" (address bindata)) (+ (first (dump foo)) 12) 4)

; foo is now ready to execute, if it is a function
; written to 'C' conventions (args are on the stack)
; arguments can be passed too.
;
; do not destroy 'bindata' or the data in it as it is
; referenced by foo

(foo)


Note, that the binary data would be the raw function binary data. You cannot just read an executable file and plug it into this. It's similar to the payload of a computer virus, just the raw code you start to execute.



You could use 'base64-enc' and 'base64-dec' to include the binary stuff in the newLISP source itself.



Instaed of loading a cell template from a library you could also get it from any built-in function, but if you want to pass parameters, is has to be from a library, or you take a built-in function template but hack the type value field to make it look like a library function. The type field is at offset 4 and has to be 264 instead of 263 for a built-in function.



Lutz

newdep

#2
Thats a great Hack ;-) Thanks a lot Lutz, Im working on it!

Ill let you know the outcome..



Norman.
-- (define? (Cornflakes))

newdep

#3
Hi Lutz,



Im trying my headoff ;-) but im only getting SegDumps...



Actualy it look slike its loading the file from the variable but then its

segdumping..mmmmm any idea?





..

.. falert.lsp is the file i want to include and execute...

.. im using the import function...

..

..

open("./imp64.lsp", O_RDONLY)           = 3

read(3, "#!/usr/bin/newlispnn(setq jelly "..., 18432) = 665

stat64("falert.lsp", {st_mode=S_IFREG|0700, st_size=691, ...}) = 0

open("falert.lsp", O_RDONLY)            = 4

read(4, "#!/usr/bin/newlispn;;n;; For the"..., 691) = 691

close(4)                                = 0

brk(0)                                  = 0x8094000

brk(0x8098000)                          = 0x8098000

brk(0)                                  = 0x8098000

brk(0x8099000)                          = 0x8099000

brk(0)                                  = 0x8099000

brk(0x809a000)                          = 0x809a000

--- SIGSEGV (Segmentation fault) @ 0 (0) ---

+++ killed by SIGSEGV +++
-- (define? (Cornflakes))

newdep

#4
Oke somethng is happening ;-)



this is my script -->



#!/usr/bin/newlisp



(setq foo (import "/lib/libc.so.6" "kill"))



(setq jelly (string (join (map (lambda (y) (string {}y)) (map (lambda (x) (format "%03d" x)) (map char (explode (read-file "falert.lsp"))))))))



;;(cpymem (pack "ld" (address jelly)) (+ (first (dump 'foo)) 12) 4)

(cpymem (pack "ld" (address jelly)) (pack "ld" (address foo)) 4)



(foo)





but the STRACE shows me an -->>>-1 ESRCH (No such process) <<<--

(I tried either of the obove cpymem both do the same..)





open("/usr/share/newlisp/init.lsp", O_RDONLY) = 3

brk(0)                                  = 0x808b000

brk(0x808f000)                          = 0x808f000

read(3, ";; init.lsp - newLISP initializa"..., 18432) = 1355

brk(0)                                  = 0x808f000

brk(0x8090000)                          = 0x8090000

open("/home/nodep/.init.lsp", O_RDONLY) = 4

brk(0)                                  = 0x8090000

brk(0x8094000)                          = 0x8094000

read(4, ";; init.lsp - newLISP initializa"..., 18432) = 1343

close(4)                                = 0

close(3)                                = 0

open("./imp64.lsp", O_RDONLY)           = 3

read(3, "#!/usr/bin/newlispnn(setq foo (i"..., 18432) = 352

stat64("falert.lsp", {st_mode=S_IFREG|0700, st_size=691, ...}) = 0

open("falert.lsp", O_RDONLY)            = 4

read(4, "#!/usr/bin/newlispn;;n;; For the"..., 691) = 691

close(4)                                = 0

brk(0)                                  = 0x8094000

brk(0x8098000)                          = 0x8098000

brk(0)                                  = 0x8098000

brk(0x8099000)                          = 0x8099000

brk(0)                                  = 0x8099000

brk(0x809a000)                          = 0x809a000

kill(134682816, 134676448)              = -1 ESRCH (No such process) <<<--- HERE !!!!!!!!!!!

close(3)                                = 0







Hope you have a hint..?



Norman
-- (define? (Cornflakes))

Lutz

#5
It has to be the first of the 'cpymem' lines. You seem to do the right thing. The problem is perhaps what youn have in jelly? I would start with some assembly instructions, i.e. just moving some values into registers AX DX for a retun value and then a ret, to see if you get the return value.



Can you do a disassembly of jelly, to see whats really in it?



How did you produce your binary? It should not be just some compiled program, but the bytes from the beginning should be executable machine code, without headers etc.



Lutz

newdep

#6
Hi Lutz,



In the problem above I used a newlisp script called falert.lsp to be executed.

(http://www.nodep.nl/downloads/newlisp/falert.lsp">http://www.nodep.nl/downloads/newlisp/falert.lsp) And thats executing newlisp first...





And when I use a binary file then its a normal compiled C file, and ELF binary

and that thus had an ELF header..(I should strip it off?)



I can try and use a raw ASM file and see what it does...



Regards, Norman.
-- (define? (Cornflakes))

newdep

#7
Hi Lutz,



I tried a simple ASM code without the ELF header but also thatone

does give me the same result as above.. (kill(....,......) = -1 ESRCH)



I like this hack very much so i hope i can get it running ;-)



If you have a hint..please let me know..



Regards, Norman.
-- (define? (Cornflakes))

Lutz

#8
The binary also has to be relocateble, no memory references outside the stack, just stripping of the header might not be enough, so your ASM code should work ... strange.



Lutz

newdep

#9
Hi Lutz,



I used Fasm for this without ELF header creation...

(fasm infile outfile)



These are not doing anything special.. but did not work..



--- nop.asm

start:

        push    eax

        xor     eax,eax

        pop eax





--- hello.asm



start:

        mov     eax,4

        mov     ebx,1

        mov     ecx,msg

        mov     edx,msize

        int     0x80



        mov     eax,1

        xor     ebx,ebx

        int     0x80



msg db 'Hello Newlisp',0xA

msize = $-msg







The code that executed the above is this ->



#!/usr/bin/newlisp



(setq foo (import "/lib/libc.so.6" "kill"))

(setq jelly (string (join (map (lambda (y) (string {}y)) (map (lambda (x) (format "%03d" x)) (map char (explode (read-file "nop"))))))))

(cpymem (pack "ld" (address jelly)) (+ (first (dump 'foo)) 12) 4)

(foo)











PS: !!! Must it be (dump 'foo) or (dump foo)? They both give a different

address range back... But im using (dump 'foo)



Perhpas its the "kill" function that causes the problem? Lets see what

I can test...



Regards, Norman.
-- (define? (Cornflakes))

Lutz

#10
It has to be (dump foo) not (dump 'foo). Do it exactly like shown in my earlier post. After this statement:



(cpymem (pack "ld" (address bindata)) (+ (first (dump foo)) 12) 4)


do:



(dump foo)
; and
(address bindata)


The last number in (dump foo) should be the same as (address bindata). What we are doing here is putting the address of the executable 'bindata' into the address, which normally points to a libray 'C' function.



I don't have a chance at the moment, but will try the stuff myself tomorrow and if possible post a working example.



Lutz

Lutz

#11
Here is a working example session:

newLISP v.8.5.10 on Win32 MinGW, execute 'newlisp -h' for more info.

> (set 'foo (import "cygwin1.dll" "kill"))
kill <610945DA>
> (set 'bindata (pack "ccccccccccc" 0x55 0x8B 0xEC 0x8B 0x45 0x08 0x03 0x45 0x0C 0x5D 0xC3))
"Uï∞ïE0803E12]├"
> (cpymem (pack "ld" (address bindata)) (+ (first (dump foo)) 12) 4)
4
> (foo 3 4)
7
> (foo 123 456)
579
>


The assembly executed is the following:



55       push epb
 8B EC    mov  ebp, esp
 8B 45 08 mov  eax, [ebp+08]
 03 45 0C add  eax, [ebp+0c]
 5D       pop  ebp
 C3       ret


This should work on Linux or any other Intel platform too. The coude has to be a callable function treating the stack and register variables as it is usual on that platform and OS.



Lutz

Lutz

#12
BTW instead of importing a library template you could use an internal function and patch the type int to library functions type:

; get a template cell from a built-in function
(set 'foo print)

; change the type to a library function
(cpymem (pack "ld" 265) (first (dump foo)) 4)

; see previous post
(set 'bindata (pack "ccccccccccc"
     0x55 0x8B 0xEC 0x8B 0x45 0x08 0x03 0x45 0x0C 0x5D 0xC3))

(cpymem (pack "ld" (address bindata)) (+ (first (dump foo)) 12) 4)

(foo 3 4) => 7

This make the whole thing more usable because you can write code without dependence of libraries.



Lutz