flat assembler
Message board for the users of flat assembler.

Index > Windows > Mystery in Kernel32

Author
Thread Post new topic Reply to topic
x0r4nd



Joined: 22 Apr 2013
Posts: 14
x0r4nd
Hello:
I come back to the temple of wisdom for advice from masters:
The attached code is a scheme (the beginning ) of a program like rundll32.exe repowered by steroids ; )
It is based on a "shellcode" whose original author name is lost in the internet labyrinth.
The aim is that by typed the name of a WIN-API (in this case from Kernel32.dll) the program will search through the dll and, when found it ,ask the parameters and then executes it.
In this first part introduces the name of the API to search.
All goes well in the beginning:
I type "WinExec" and then it scroll through the list of names in Kernel32 apis and it stops and report that was found.
If I type again "WinExec" there are no problems.
If after having found "WinExec" I type (for example) "WriteConsoleA" finds it ....
BUT if again trying to find "WinExec" it can not find or do not stop and continues until the last api ("lstrlenW"), where for a trap, back to the beginning.
I've noticed that : Need to go three times through the entire apis list to again find WinExec (ie pressing <enter> three times).
The problem is compounded if after finding "WinExec" I ask to find the latest in the list of APIS from Kernel32 ( "lstrlenW") henceforth never again find "WinExec".
Seems to be a chaotic behavior which can not permit be confident about that the program will find the following api.
I made all kinds of changes in the size of the buffers; about the form of comparing the strings, about the way to find a handle to Kernel32, et.etc. etc.
and always encounter the same problem: Chaotic Behavior.
There are explanation and solution for this problem??
Thanks in advance.
( Original en Español, TRANSLATED BY GOOGLE TRANSLATOR, I apologize about the mistakes)
Code:
format PE console
include 'win32ax.inc'
.data
control TCHAR "lstrlenW",0
salto TCHAR 10,13
apix  rb 127
escrito DD ?
handy DD ?
apw DD ?
.code
;======================================================
           start:
           invoke GetModuleHandle,"kernel32.dll"
           mov [handy],eax
           proceso:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
          invoke WriteConsole,7,[handy],4,4,0        ;
          invoke WriteConsole,7,salto,2,2,0          ;
          invoke WriteConsole,7,"API ? ",6,6,0       ;
          invoke ReadConsole,3,apix,127,escrito,0    ;
          push apix                                  ;
          call [lstrlen]                             ;
          dec eax                                    ;
          mov [escrito],eax                          ;
          invoke lstrcpyn,apix,apix,eax              ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
          call llamada                               ;
          .end start                                 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
llamada:
   popad
   mov eax,[handy]
   mov ebp, eax
   mov eax, [ebp+3ch]
   mov eax, [eax+ebp+78h]
   add eax, ebp
   mov ecx, eax
   mov eax, [eax+20h]
   add eax, ebp
   mov ebx, eax
;;;;;;;;;;;;;;;;;;;;;;;;;;;
   sfunc:                 ;
   xor edi, edi           ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;
   finhsh:                ;
   inc edi                ;
   mov esi, [ebx+edi*4]   ;
   add esi, ebp           ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   mostrar:                                              ;
   pushad                                                ;
   mov [apw],esi                                         ;
   invoke WriteConsole,7,[apw],10,10,0                   ;
   invoke WriteConsole,7,salto,2,2,0                     ;
                   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   push [escrito]       ;ByVal cchCount2 As Long  ;-1    ;
   push apix            ;ByVal lpString2 As String       ;
   push [escrito]       ;ByVal cchCount1 As Long  ;-1    ;
   push [apw]           ;ByVal lpString1 As String ;esi  ;
   push 0x01            ;ByVal dwCmpFlags As Long,       ;
   push 0x0400          ;ByVal Locale As Long,           ;
   call [CompareString] ;As Long                         ;
   cmp eax,2            ;Const CSTR_EQUAL = 2            ;
   je proceso ; start                                    ;
                   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   invoke lstrcmp,esi,control                            ;
   cmp eax,0                                             ;
   je proceso ;start                                     ;
                  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   popad                                                 ;
   xor esi,esi                                           ;
   jmp finhsh                                            ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;    
Post 08 Jun 2013, 18:14
View user's profile Send private message Reply with quote
x0r4nd



Joined: 22 Apr 2013
Posts: 14
x0r4nd
Hello, anyone living in this win-planet?
Perhaps I was disrespectful?
or
My question is too silly?
Post 12 Jun 2013, 15:51
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr
x0r4nd wrote:
Perhaps I was disrespectful?
or
My question is too silly?
Neither, it just requires some time to investigate. Wink
Post 12 Jun 2013, 18:48
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 2915
Location: [RSP+8*5]
bitRAKE
ReadConsole does not null terminate the input, so escrito often includes erroneous characters. This is compounded by using longer API name and then a shorter one - because the input buffer is still dirty. Some rudimentary filtering on the input is needed to correctly determine API string length.

Following your sequence of testing: You can verify this by halting after ReadConsole, after the second entry of "WinExec". Look at apix buffer. Then see that lstrlen returns a value of 11 for length. We are sometimes unlucky to have code work when it shouldn't - hiding errors.

_________________
¯\(°_o)/¯ unlicense.org
Post 12 Jun 2013, 21:32
View user's profile Send private message Visit poster's website Reply with quote
x0r4nd



Joined: 22 Apr 2013
Posts: 14
x0r4nd
BitRAKE Thanks for your reply:
About your opinion I inform you:
Following the introduction of APIX via console it is reduced in 1 byte the buffer size through by calls to lstrlen and lstrcpyn
I have tried several ways to overcome this problem: Conserving "APIX" in its original size and copying it reduced in 1 byte to another variable,
then it is twice compared the name in ESI against original APIX and against reduced APIX .
I've also cleaned up the buffer in every way possible form and never get to find WinExec again.
I definitely think that this is not the real cause of strange behavior.
Post 12 Jun 2013, 22:48
View user's profile Send private message Reply with quote
x0r4nd



Joined: 22 Apr 2013
Posts: 14
x0r4nd
I have also changed the way of comparing the two strings: as you will see in the posted version use both CompareString and lstrcmp.
By using CompareString can push "-1" instead of the size of the strings and the api find real sizes. Nor how it works.
The strange thing is that it never stops working properly lstrcmp "control" against the string in ESI. In a latest version I'm using ordinal numbers and seems to work "a little" better
Post 12 Jun 2013, 23:01
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 2915
Location: [RSP+8*5]
bitRAKE
The simplest solution would be to use the number of bytes returned by ReadConsole - it will tell of bytes read. On my system ReadConsole puts 13,10 at end of "WinExec", so a reduction by one byte solves nothing. Furthermore, lstcmp and lstrlen require null strings, and no such formating is guaranteed by your code. The fact that it works sometimes is misleading and anecdotal.

_________________
¯\(°_o)/¯ unlicense.org
Post 13 Jun 2013, 03:05
View user's profile Send private message Visit poster's website Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2913
Location: 0x77760000
typedef
Logical errors!

Also Why not implement some sort of "caching". Sofor each API you return you create a simple LONG hash and store it. Padd it with the ordinal of the API so if the hash matches just call it by the ordinal.
Post 13 Jun 2013, 09:53
View user's profile Send private message Reply with quote
x0r4nd



Joined: 22 Apr 2013
Posts: 14
x0r4nd
bitRAKE:
I added the following line after entering APIX by console: "invoke lstrcat APIX,pito" where "pito" is defined as TCHAR 0,0 in Data segment.
The behavior remains the same.
typedef:
As I said in the previous post I'm working on a new version seeking the api by its ordinal number or HINT (from what report depends.exe).
So there is no mistake: the API is always find.
The logic say that ; By just manually type the name of the api and call GetProcAddress should be able to invoke it.
But it took months trying and have not succeed.
I do not get it either typing the ordinal number and calling for "atoi".
I think that : there are some hidden protection mechanism by Microsoft.
For all that I chose to use this system shellcode style
Post 13 Jun 2013, 14:46
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1409
Location: Toronto, Canada
AsmGuru62
This code may cause undefined behaviour:
Code:
;
; buffer apix is copied into itself. Weird...
;
invoke lstrcpyn,apix,apix,eax
    

Please check the 'Remarks' here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms647491(v=vs.85).aspx

Also,
Code:
invoke WriteConsole,7,[handy],4,4,0
    

Does this code really runs?
The '7' is a handle for console output buffer.
I think it should be received by calling GetStdHandle -- is it not?
The second '4' according to MSDN must be a pointer to a DWORD to receive some information.
I am not sure that '4' is a pointer here.
Post 13 Jun 2013, 15:48
View user's profile Send private message Send e-mail Reply with quote
x0r4nd



Joined: 22 Apr 2013
Posts: 14
x0r4nd
AsmGuru62:
1.- invoke lstrcpyn,apix,apix,eax : This code works (I checked with Ollydbg) and works better than using a different variable for the buffer to copy, mainly because it is copying a smaller number of bytes (dec eax).
2. - Loking with Ollydbg I noticed is always designated 7 as output Standar handle. Works perfectly , also 3 as handle of ReadConsole.
It's about reducing bytes, optimize code and get efficiency.
Regards...
Post 13 Jun 2013, 16:20
View user's profile Send private message Reply with quote
x0r4nd



Joined: 22 Apr 2013
Posts: 14
x0r4nd
AsmGuru62:
About the second "4" , you are rigth, but..... it works !!!!???
I will correct it hereinafter.
Added: I've corrected it and continues the same erratic behavior.
Post 13 Jun 2013, 16:28
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 2915
Location: [RSP+8*5]
bitRAKE
x0r4nd wrote:
bitRAKE:
I added the following line after entering APIX by console: "invoke lstrcat APIX,pito" where "pito" is defined as TCHAR 0,0 in Data segment.
The behavior remains the same.
If you add a zero to an undefined array it is still undefined.

_________________
¯\(°_o)/¯ unlicense.org
Post 13 Jun 2013, 17:22
View user's profile Send private message Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1409
Location: Toronto, Canada
AsmGuru62
xOr4nd:
Always follow MSDN and your code will be better.
If MSDN says that lstrcpyn sometimes causing issues when buffers overlap, then you should believe it.
It does not matter that it works now.
It will not work later on some different OS.
Same thing with 7 as a handle. May not always be 7.
I am debugging the code right now -- there are more issues, like I think
that your code is recursive, i.e. it calls itself without returning from a function
by just jumping to a label. Not good. I'll post some more results later.
Post 13 Jun 2013, 17:31
View user's profile Send private message Send e-mail Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1409
Location: Toronto, Canada
AsmGuru62
It is working code (see my comments marked by 'ag62'):
Code:
; ---------------------------------------------------------------------------
; FILE: A1.Asm
; DATE: June 13, 2013
; ---------------------------------------------------------------------------

format PE console
entry   start

    include 'Win32AX.Inc'

; ---------------------------------------------------------------------------
section '.data' data readable writeable

hIn dd 0
hOut dd 0
control TCHAR "lstrlenW",0
str_Module TCHAR "kernel32.dll",0
str_Ask TCHAR "API: ",0
str_Stop TCHAR "cmon",0
strGotIt TCHAR 13,10,13,10,"=== GOT IT !! ===",13,10,13,10,0
salto TCHAR 10,13
apix  rb 127
nBytes DD ?
escrito DD ?
handy DD ?
apw DD ?

; ---------------------------------------------------------------------------
section '.code' code readable executable

;======================================================
           start:
           ;
           ; Get Console handles (just in case)
           ;
           invoke GetStdHandle, STD_OUTPUT_HANDLE
           mov [hOut],eax
           invoke GetStdHandle, STD_INPUT_HANDLE
           mov [hIn],eax

           invoke GetModuleHandle,str_Module
           mov [handy],eax
           proceso:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
          invoke WriteConsole,[hOut],[handy],4,nBytes,0
          invoke WriteConsole,[hOut],salto,2,nBytes,0
          invoke WriteConsole,[hOut],str_Ask,5,nBytes,0
          invoke ReadConsole,[hIn],apix,127,escrito,0
          ;
          ;[ag62]
          ; The value of [escrito] will always include 0Dh,0Ah
          ; Reduce it by 2 bytes and store it back to [escrito]
          ;
          mov eax, [escrito]
          sub eax, 2
          mov [escrito], eax
          ;
          ; Now terminate the text at apix by 00h
          ;
          mov [eax + apix], ah
          ;
          ; lets terminate if you type "cmon"
          ;
          invoke lstrcmp, str_Stop, apix
          test eax, eax
          jz kill_me
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
          call llamada                               ;
          jmp kill_me   ; [ag62] -- unreachable code!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
llamada:
   ;popad      [ag62: why? PUSHAD is never used before calling it]
   mov eax,[handy]
   mov ebp, eax
   mov eax, [ebp+3ch]
   mov eax, [eax+ebp+78h]
   add eax, ebp
   mov ecx, eax
   mov eax, [eax+20h]
   add eax, ebp
   mov ebx, eax
;;;;;;;;;;;;;;;;;;;;;;;;;;;
   sfunc:                 ;
   xor edi, edi           ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;
   finhsh:                ;
   inc edi                ;
   mov esi, [ebx+edi*4]   ;
   add esi, ebp           ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   mostrar:                                              ;
   pushad                                                ;
   mov [apw],esi                                         ;
   ;
   ; [ag62] So, every API name in KERNEL32 is 10 characters?
   ; lets count them and pass a proper parameter.
   ;
   invoke lstrlenA, esi
   invoke WriteConsole,[hOut],esi,eax,nBytes,0
   invoke WriteConsole,[hOut],salto,2,nBytes,0
                   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   push [escrito]       ;ByVal cchCount2 As Long  ;-1    ;
;   push apix            ;ByVal lpString2 As String       ;
;   push [escrito]       ;ByVal cchCount1 As Long  ;-1    ; [ag62] must be lstrlenA(apw)
;   push [apw]           ;ByVal lpString1 As String ;esi  ;
;   push 0x01            ;ByVal dwCmpFlags As Long,       ;
;   push 0x0400          ;ByVal Locale As Long,           ;
;   call [CompareString] ;As Long                         ;
;   cmp eax,2            ;Const CSTR_EQUAL = 2            ;
;   je proceso ; start                                    ;

    ;
    ; [ag62] just using the good old Win API
    ;

   invoke lstrcmp,esi,apix
   test eax, eax
   jz found_apix

    ;
    ; [ag62]
    ; so, 'lstrlenW' is the last one in K32?
    ; if not (in other OS version) -- your code will be looking beyond 'lstrlenW'.
    ;
                   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   invoke lstrcmp,esi,control                            ;
   cmp eax,0                                             ;
   ;
   ; [ag62] You're JMP-ing to outside label from a CALL-ed function.
   ; I'll do the same at 'found_apix' label, but you need to try to
   ; do it properly. Also, how do you end this code? what do
   ; you type at "API" prompt to end it?
   ;
   je proceso ;start                                     ;
                  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   popad                                                 ;
   jmp finhsh                                            ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

found_apix:
   invoke lstrlenA, strGotIt
   invoke WriteConsole,[hOut],strGotIt,eax,nBytes,0
    jmp proceso

kill_me:
    invoke    ExitProcess, 0

; ---------------------------------------------------------------------------
section '.idata' import data readable writeable

    library kernel32,'KERNEL32.DLL',user32,'USER32.DLL'

    include 'API\Kernel32.Inc'
    include 'API\User32.Inc'


    
Post 13 Jun 2013, 18:44
View user's profile Send private message Send e-mail Reply with quote
x0r4nd



Joined: 22 Apr 2013
Posts: 14
x0r4nd
Thank you very much AsmGuru62.
Your code works perfectly. It is a great help.
I hope to finish my project and post it for more advice and refine.
As you know every step in the way there are new obstacles, much more to me that I am just learning assembly, I never understood the C + + and all my knowledge was limited to some VBA and VBscript.
Apologize for the language mistakes , I write in Spanish and translate it via Google.
Added some comments to your comments.

Quote:
;[ag62]
; The value of [escrito] will always include 0Dh,0Ah
; Reduce it by 2 bytes and store it back to [escrito]
X0r4nd : UNDERSTOOD, My mistake: I just reduced 1 byte
...............
call llamada ;
jmp kill_me ; [ag62] -- unreachable code!
X0rd4n : ??????
..........................
;popad [ag62: why? PUSHAD is never used before calling it]
x0r4nd: this is a "fossil" from the many changes I made looking for the solution; actually makes no sense.
...........................
; [ag62] just using the good old Win API
X0r4nd: CompareString is case insensitive. I tried this api and all of the family "lstrcmp" and other apis from other dlls looking for the solution.
..................................
; [ag62]
; so, 'lstrlenW' is the last one in K32?
; if not (in other OS version) -- your code will be looking beyond 'lstrlenW'
Yeah, it is a temporary solution while I find another. I have also used the number 1359 compared to "edi" (lstrlenW ordinal)
.

..............................
; [ag62] You're JMP-ing to outside label from a CALL-ed function.
; I'll do the same at 'found_apix' label, but you need to try to
; do it properly.
X0rd4n: Yeah , in other versions I used "jmp" and other ways to terminate or continue.
; [ag62] Also, how do you end this code? what do you type at "API" prompt to end it?
X0rd4n: typing Ctrl C (it's a joke ; ) ...
Actually, as I said in the first post, this is just the first part of a program that I am trying to build like rundll32.exe but interactive:
In the version that I am currently handling where the API is search by the Hint number , first introduced the name of the library (is posible in this version scan another dlls), then the Hint; if find the API then parameters are introduced, they are pushed to the stack and then call the API and (SOME TIMES Wink it run.
Finaly return to the main screen asking for new DLL and/or new API.
Of course there will be a magic word to end (what mean's "cmon"? Might use this)
..........
Post 13 Jun 2013, 22:39
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1409
Location: Toronto, Canada
AsmGuru62
Great research!
I'll try to answer some of your questions.

1. Once llamada is called it never returns back. You use JMP to return back to the asking which API must be located.
Therefore code AFTER call to llamada cannot be reached, such case is called an unreachable code.

2. lstrcmp or CompareString? It depends on your needs.
For example, if you type "HeapFree" running the code I posted - it will be found by lstrcmp.
but if you type "heapfree" - it will not be found, but CompareString will find it.

3. "cmon" is short for this (it has quite a lot of meanings):
http://thesaurus.com/browse/come+on?s=t&path=/
Post 14 Jun 2013, 00:41
View user's profile Send private message Send e-mail Reply with quote
x0r4nd



Joined: 22 Apr 2013
Posts: 14
x0r4nd
Again thanks to you asmguru62 and all who contribute with their ideas and advice.
Where do I find the button to mark solved the topic?
Post 14 Jun 2013, 17:22
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1409
Location: Toronto, Canada
AsmGuru62
I am not sure these forums have such feature.
Post 14 Jun 2013, 17:34
View user's profile Send private message Send e-mail Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2913
Location: 0x77760000
typedef
x0r4nd wrote:
Again thanks to you asmguru62 and all who contribute with their ideas and advice.
Where do I find the button to mark solved the topic?


Do it my way. Add this to the topic: [SOLVED]
Post 14 Jun 2013, 21:49
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar.

Powered by rwasa.