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! :)
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$