Saturday, October 13, 2018

Windows assembly tips


Hello all,

I am "briefly back" to the blog... Before we start, if you like (or do not like) my blog/articles or you have comments on it, please drop me an email at gnomicbits@gmail.com.

I was yearning to update this blog for sometime now, with some new learning. Much of the new musings are around system/software security. But then I thought to hold it off for some more time so that I can provide you better content.

Meanwhile, I was getting back to my "routine coding on assembly". I always miss assembly. I try my best to see where I can "plug-in" some assembly coding whether it be at work or it be training/seminars or  sometimes I even try to introduce it during small talks.

Recently I was writing some simple utilities at work. These are designed to be support tools for some earlier work. So there is "nothing official" about the development. It simply caters to troubleshooting the existing software stack. Thus it was a good excuse for me to write it in assembly language.

So what I plan this time for this article, is to have this as a "rolling article" (assuming you already know assembly) where I keep updating this article with new ideas or tips. So keep checking this page, whenever you can because "writing assembly" is like morning constitutionals for me. You may see new tips. I am looking forward to learn from you readers too . If you feel, I could improve somewhere or I have gone wrong somewhere, please drop me an email with the details. I will definitely revert.

Well.. I think this preface is enough for you to get some context on why/how I am back. Let us get started....

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

TIP#1:- One of the most sought-after code in GUI-programming, especially when we create our own utilities is - how to center the window and make it the top most window. And most of us would have copied and saved this code from the MVP blogs several years back or may have rehearsed more than once, the algorithm we use, to do this. So some of this may be repetitive work for some of you... While I am sure there are code snippets out there, in the internet , I will try to make this more useful by annotating the code so you can read the code and its explanation "at the same time"...


;;;;; { The procedure we call to center the window and make it the "top-most"};;;;;;

;;;;; { Takes one argument that is the window handle} ;;;;;;;;;;

SetMainWinSizeAndPosition proc uses edi  hwnd:HWND


;;;;;;;;; Declare the locals ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LOCAL hdc:HDC
LOCAL screenwd:DWORD
LOCAL screenht:DWORD
LOCAL winwd:DWORD
LOCAL winht:DWORD
LOCAL winx:DWORD
LOCAL winy:DWORD
LOCAL sizemult:DWORD
LOCAL sizediv:DWORD

;;;;;; Strategy :-

;;;;;;;  (1) Sizing the window :- While you can pass any values for the width and height, here I use
;;;;;;;  the screen resolution and make the window width and height as 1/3rd of the "screen sizes"
;;;;;;;
;;;;;;;  (2) Positioning it in the center of the screen :- Imagine the cartesian plane and your window ;;;;;;;  on it. Assume that we
;;;;;;;  have a finite width and height for this plane since we superimpose your screen with the
;;;;;;;  cartesian plane on top of it; If we half the screen width we get the "x-coord" and
;;;;;;;  if we half the screen height
;;;;;;;  we get the "y-coord".  If we simply made these values the x & y then the top left corner of our
;;;;;;;  window will be in center not the window itself! So we need to also half the width and height of
;;;;;;;  our window and subtract that from the previously calculated x & y.
;;;;;;;  Technically we shouldn't assume that the x and y coordinates are at the center of the screen
;;;;;;;  when we try to superimpose the imaginary cartesian plane. The coordinates and the "layout"
;;;;;;;  depends upon the "mapping mode". I won't digress to that topic here.
;;;;;;;
;;;;;;;
;;;;;;;  (3) Making it top most :- Simply pass a flag to a Windows API!

;;;;;;;  Windows APIs - GetDC(), ReleaseDC(), GetDeviceCaps() and SetWindowPos().

;;;;;;;  Have the multiplier and divider set.. it is 1/3rd and we can simply set this value to anything
;;;;;;;  else later

 mov sizemult,1
 mov sizediv,3

;;;;;;;; We need to first get the device context of the window. From this we can get the device
;;;;;;;; capabilities which will include the horizontal and vertical screen resolutions
;;;;;;;;

 invoke GetDC,hwnd
 mov hdc,eax
 invoke GetDeviceCaps,hdc,HORZRES
 mov screenwd,eax ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  screen width
 invoke GetDeviceCaps,hdc,VERTRES
 mov screenht,eax ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; screen height


 ;;;Sizing the window
        ;;; Multiply by "multiplier" and divide by the "divider".

 mov eax,screenwd
 mul sizemult
 div sizediv
 mov winwd,eax  ;;;;;;;;; save the window's width


 mov eax,screenht
 mul sizemult
 div sizediv
 mov winht,eax    ;;;;;;;;;;;; save the window's height


 ;;;Centering the window

        ;;;;;;;;;;;;;; Use an optimization (shr) this time instead of  div
        ;;;;;;;;;;;;;;;

 mov eax,screenwd
 mov winx,eax
 shr winx,1       
 mov eax,winwd
 shr eax,1
 sub winx,eax


 mov eax,screenht
 mov winy,eax
 shr winy,1
 mov eax,winht
 shr eax,1
 sub winy,eax


 ;;; Now set size and position of the window and make it
 ;;; the "top most" window

 push 0
 push winht
 push winwd
 push winy
 push winx
 push HWND_TOPMOST
 push hwnd
 call SetWindowPos

 push hdc
 push hwnd
 call ReleaseDC

 Ret
SetMainWinSizeAndPosition endp


$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$


TIP#2:- Now for an interesting GUI hack. You see a few applications with "grayed off buttons" on their dialog boxes and windows, probably as an attempt to tell you that you are using a trial version of their software. The app might require you to register to ensure the buttons are enabled etc. How to enable these disabled/grayed off buttons etc.?

This is a very simple and ugly hack for "standard controls" like buttons. This means you can't use this trick for "custom controls". The typical "button" you see when you get error message pop ups from shell/explorer etc is an example of a standard control - class Button. And this works on windows related to the current thread's desktop. Thus if you are looking at enabling these "disabled buttons" you can use below program and that is the entire program (add the headers/sections etc).

start:
invoke MessageBox,0,addr Message,addr AppName,0

;Enumerate all top level windows, and on each enum, enumerate
;all child windows and pass WM_ENABLE message

invoke EnumWindows,OFFSET EnumWindowsProc,0
invoke ExitProcess,0

EnumWindowsProc proc hwnd:HWND,lparam:LPARAM
push 0
push OFFSET EnumChildProc
push hwnd
call EnumChildWindows

mov eax,TRUE
Ret
EnumWindowsProc endp


EnumChildProc proc hwnd:HWND,lparam:LPARAM
push 1
push hwnd
call EnableWindow

mov eax,TRUE
Ret
EnumChildProc endp

end start

There are other complex code written by authors for the same purpose using hooks. They may serve a more complex scenario. But to simply enable these buttons etc, the above code is enough. If you still want an executable to see it in action you can download EnableAll.zip from below location.
https://sites.google.com/site/gnomicbits/downloads

Note:- I had chrome open while testing this and the pages simply froze.Use judiciously!

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$


TIP#3:- How to check if the current thread has "admin" rights?

What I assume here is that the reader is looking for a way to determine if her/his code has certain "admin rights" For example: for creating a folder in say "Program files" directory or so. We also can determine if we are running on an "elevated mode" under "UAC". Starting Windows Vista, most programs we execute go through a "UAC" layer that intentionally runs the program with "least privilege security". This means the program (probably a malware) won't do evil things easily. UAC would try to gain the "user attention" by throwing pop-ups asking for "elevation" or sometimes it silently stops executing the program and so on. Thus as a developer you may want to check if the code is running in an "elevated mode". I have annotated the code to some extent. I will try to provide detailed theory on Windows security in a future article.

I use the same example provided in msdn here
MSDN ref: https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-checktokenmembership

IsRunningAsAdmin proc

LOCAL AdministratorsGroup:SID
LOCAL xyz:ptr SID

lea ebx,AdministratorsGroup
mov xyz,ebx

;;; First get SID for local administrators group
lea edx,xyz
push edx
push 0
push 0
push 0
push 0
push 0
push 0 
push DOMAIN_ALIAS_RID_ADMINS         
push SECURITY_BUILTIN_DOMAIN_RID  ;;;security boundary via RID
push 2 ;;;;sub authorities count 
lea edx,NtAuthority ;;;;top level authority. "5"
push edx
call AllocateAndInitializeSid

.if (eax)

;;; Now check if our token has the above SID in its membership list. A thread has an associated
;;; token that it gains from its parent process or through impersonation. In this example (msdn)
;;; we assume we are using our own token (thread)

lea edx,bAdmin
push edx
push xyz
push NULL
call CheckTokenMembership

.if !eax
MsgBox addr err
.endif

.if bAdmin
MsgBox addr isadmin
.else
MsgBox addr isnotadmin
.endif
.endif

push xyz
call FreeSid

Ret
IsRunningAsAdmin endp

We also have defined below variables in the data and bss sections

NtAuthority SID_IDENTIFIER_AUTHORITY <SECURITY_NT_AUTHORITY>
bAdmin BOOL ?

Below is a demo of the above code executed in a normal and an elevated command prompt displayed side-by-side



$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$


TIP#4:- Ok now something that most of you would love, especially assembly enthusiasts who are still learning up assembly or struggling to cross the Beginner-Intermediate zone (like me)!
How to use Kip Irvine's resources with MASM SDK? :)

While he has given fantastic hacks with VS projects and you could just start with community edition you may still feel that that IDE is no better than Winasm. Yet you would still (if you are like me) love to use Qeditor to write your programs. Irvine's book including the libraries and macros are really good for beginners as well as pr0f3ss10n4l c0d3rs ;) ;).  So to rephrase the problem, how to integrate the resources so that you can use masm sdk with Irvine32 lib. Follow steps below

1) Copy all the .inc files to MASM include
2) Copy all the .lib files except for user32 and kernel32 because we already have them. I never
got time to look into why they are larger than the SDK's.
3) Include only Irvine<##>.inc in the code which in turn includes SmallWin.inc etc.
4) Ensure to include libraries as needed like kernel32...
5) Ensure to include Irvine<##>.lib too.
6) When you are using Qeditor do "Console assemble and link" not the regular one because
he has written console based sample programs mostly.

That's it and it worked for me for quite a few samples.

Meanwhile I am just trying Hutch's new x64 kit in tandem with Vasily Sotnikov's version of MASM sdk. That way you get all the incs and libs as needed :) Yeah I am too lazy! :)


$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$