     1                                  ; messagebox_x64.asm — position-independent x64 shellcode: resolve
     2                                  ; user32.dll!MessageBoxA via LoadLibraryA (user32.dll isn't guaranteed
     3                                  ; loaded in a plain console process, unlike kernel32) and pop a real
     4                                  ; message box. Returns normally (ret) once the user dismisses it, so the
     5                                  ; host thread keeps running afterward.
     6                                  ;
     7                                  ; text_buf/caption_buf are fixed-size placeholders at the very end of the
     8                                  ; assembled blob; winpwn patches them at runtime with the actual
     9                                  ; NUL-terminated strings (see shellcraft.go).
    10                                  BITS 64
    11                                  default rel
    12                                  
    13                                  start:
    14 00000000 55                          push rbp
    15 00000001 4154                        push r12
    16 00000003 4889E5                      mov rbp, rsp
    17 00000006 4883E4F0                    and rsp, ~0xF           ; force 16-byte stack alignment, unknown entry state
    18                                  
    19 0000000A E83F000000                  call get_kernel32_base
    20 0000000F 4889C1                      mov rcx, rax
    21 00000012 488D1551010000              lea rdx, [rel name_user32]
    22 00000019 4C8D0555010000              lea r8, [rel name_messageboxa]
    23 00000020 E8CE000000                  call resolve_export
    24 00000025 4989C4                      mov r12, rax            ; r12 = MessageBoxA address
    25                                  
    26 00000028 4831C9                      xor rcx, rcx              ; hWnd = NULL
    27 0000002B 488D1556010000              lea rdx, [rel text_buf]   ; lpText
    28 00000032 4C8D054F020000              lea r8, [rel caption_buf] ; lpCaption
    29 00000039 4D31C9                      xor r9, r9                ; uType = MB_OK
    30 0000003C 4883EC20                    sub rsp, 0x20              ; shadow space required before any WinAPI call
    31 00000040 41FFD4                      call r12
    32 00000043 4883C420                    add rsp, 0x20
    33                                  
    34 00000047 4889EC                      mov rsp, rbp
    35 0000004A 415C                        pop r12
    36 0000004C 5D                          pop rbp
    37 0000004D C3                          ret
    38                                  
    39                                  %include "resolver.inc"
     1                              <1> ; resolver.inc — shared x64 position-independent building blocks for winpwn
     2                              <1> ; shellcraft templates: find kernel32's base via the PEB (no hardcoded
     3                              <1> ; addresses) and resolve any export by name (no hashing, just a linear
     4                              <1> ; name-table scan — simple, auditable, and plenty fast for a handful of
     5                              <1> ; one-shot resolutions).
     6                              <1> ;
     7                              <1> ; Calling convention (our own, not WinAPI): standard x64 fastcall-ish,
     8                              <1> ; args in RCX/RDX, result in RAX. Both routines preserve every
     9                              <1> ; non-volatile register they touch, so callers can keep values live in
    10                              <1> ; r12-r15 across calls to either of these.
    11                              <1> 
    12                              <1> ; get_kernel32_base() -> RAX = kernel32.dll base address
    13                              <1> ;
    14                              <1> ; Walks PEB->Ldr->InMemoryOrderModuleList. Entry 0 is always the running
    15                              <1> ; executable itself, entry 1 is ntdll.dll, entry 2 is kernel32.dll — this
    16                              <1> ; fixed load order is the same trick essentially every public Windows x64
    17                              <1> ; shellcode relies on.
    18                              <1> get_kernel32_base:
    19 0000004E 65488B042560000000  <1>     mov rax, [gs:0x60]      ; TEB->ProcessEnvironmentBlock (gs:0x60 on x64)
    20 00000057 488B4018            <1>     mov rax, [rax+0x18]     ; PEB->Ldr
    21 0000005B 488B4020            <1>     mov rax, [rax+0x20]     ; Ldr->InMemoryOrderModuleList.Flink -> entry0.InMemoryOrderLinks
    22 0000005F 488B00              <1>     mov rax, [rax]          ; entry0.Flink -> entry1 (ntdll.dll)
    23 00000062 488B00              <1>     mov rax, [rax]          ; entry1.Flink -> entry2 (kernel32.dll)
    24 00000065 488B4020            <1>     mov rax, [rax+0x20]     ; entry2.DllBase  (DllBase sits 0x20 past InMemoryOrderLinks)
    25 00000069 C3                  <1>     ret
    26                              <1> 
    27                              <1> ; find_export(RCX = module base, RDX = pointer to NUL-terminated ASCII name)
    28                              <1> ;   -> RAX = absolute address of the export, or 0 if not found.
    29                              <1> ;
    30                              <1> ; Walks IMAGE_EXPORT_DIRECTORY.AddressOfNames linearly comparing each
    31                              <1> ; entry against the target string, then follows AddressOfNameOrdinals and
    32                              <1> ; AddressOfFunctions to the RVA. NT_HEADER+0x88 is the canonical
    33                              <1> ; DataDirectory[0] (export table) offset for PE32+.
    34                              <1> find_export:
    35 0000006A 4154                <1>     push r12
    36 0000006C 4155                <1>     push r13
    37 0000006E 4156                <1>     push r14
    38 00000070 4157                <1>     push r15
    39 00000072 56                  <1>     push rsi
    40 00000073 57                  <1>     push rdi
    41 00000074 53                  <1>     push rbx
    42                              <1> 
    43 00000075 4989CC              <1>     mov r12, rcx            ; r12 = module base (preserved for the whole routine)
    44 00000078 4989D5              <1>     mov r13, rdx            ; r13 = target name pointer (preserved)
    45                              <1> 
    46 0000007B 418B44243C          <1>     mov eax, [r12+0x3C]     ; e_lfanew
    47 00000080 4C01E0              <1>     add rax, r12            ; rax = NT header VA
    48 00000083 8B8088000000        <1>     mov eax, [rax+0x88]     ; export dir RVA (OptionalHeader64.DataDirectory[0].VirtualAddress)
    49 00000089 4C01E0              <1>     add rax, r12
    50 0000008C 4989C6              <1>     mov r14, rax            ; r14 = export directory VA
    51                              <1> 
    52 0000008F 418B5E18            <1>     mov ebx, [r14+0x18]     ; ebx = NumberOfNames
    53 00000093 458B4E20            <1>     mov r9d,  [r14+0x20]    ; AddressOfNames RVA
    54 00000097 4D01E1              <1>     add r9, r12             ; r9  = AddressOfNames VA  (array of DWORD RVAs -> name strings)
    55 0000009A 458B5624            <1>     mov r10d, [r14+0x24]    ; AddressOfNameOrdinals RVA
    56 0000009E 4D01E2              <1>     add r10, r12            ; r10 = AddressOfNameOrdinals VA (array of WORD ordinals)
    57 000000A1 458B5E1C            <1>     mov r11d, [r14+0x1C]    ; AddressOfFunctions RVA
    58 000000A5 4D01E3              <1>     add r11, r12            ; r11 = AddressOfFunctions VA (array of DWORD RVAs -> code)
    59                              <1> 
    60 000000A8 4D31FF              <1>     xor r15, r15            ; r15 = loop index i
    61                              <1> 
    62                              <1> .loop:
    63 000000AB 4939DF              <1>     cmp r15, rbx
    64 000000AE 7D34                <1>     jge .notfound
    65                              <1> 
    66 000000B0 438B04B9            <1>     mov eax, [r9 + r15*4]   ; nameRVA for entry i
    67 000000B4 4C01E0              <1>     add rax, r12
    68 000000B7 4889C6              <1>     mov rsi, rax            ; rsi = candidate name VA
    69 000000BA 4C89EF              <1>     mov rdi, r13            ; rdi = target name VA (reset every attempt)
    70                              <1> 
    71                              <1> .cmp_loop:
    72 000000BD 8A06                <1>     mov al, [rsi]
    73 000000BF 8A0F                <1>     mov cl, [rdi]
    74 000000C1 38C8                <1>     cmp al, cl
    75 000000C3 750C                <1>     jne .next
    76 000000C5 84C0                <1>     test al, al
    77 000000C7 740D                <1>     je .found               ; both hit NUL with every byte equal -> match
    78 000000C9 48FFC6              <1>     inc rsi
    79 000000CC 48FFC7              <1>     inc rdi
    80 000000CF EBEC                <1>     jmp .cmp_loop
    81                              <1> 
    82                              <1> .next:
    83 000000D1 49FFC7              <1>     inc r15
    84 000000D4 EBD5                <1>     jmp .loop
    85                              <1> 
    86                              <1> .found:
    87 000000D6 4B0FB7047A          <1>     movzx rax, word [r10 + r15*2]  ; ordinal index for entry i
    88 000000DB 418B0483            <1>     mov eax, [r11 + rax*4]          ; function RVA
    89 000000DF 4C01E0              <1>     add rax, r12                     ; absolute address
    90 000000E2 EB03                <1>     jmp .done
    91                              <1> 
    92                              <1> .notfound:
    93 000000E4 4831C0              <1>     xor rax, rax
    94                              <1> 
    95                              <1> .done:
    96 000000E7 5B                  <1>     pop rbx
    97 000000E8 5F                  <1>     pop rdi
    98 000000E9 5E                  <1>     pop rsi
    99 000000EA 415F                <1>     pop r15
   100 000000EC 415E                <1>     pop r14
   101 000000EE 415D                <1>     pop r13
   102 000000F0 415C                <1>     pop r12
   103 000000F2 C3                  <1>     ret
   104                              <1> 
   105                              <1> ; resolve_export(RCX = kernel32 base, RDX = DLL name ptr or 0, R8 = func name ptr)
   106                              <1> ;   -> RAX = absolute address of the export, or 0 on any failure.
   107                              <1> ;
   108                              <1> ; find_export alone only works if the target module is *already* loaded
   109                              <1> ; into the process -- fine for kernel32 itself, not fine for e.g. user32.dll
   110                              <1> ; in a plain console process. When RDX is 0 this is exactly find_export
   111                              <1> ; (the function is assumed already loaded at the module base in RCX).
   112                              <1> ; When RDX is a DLL name pointer, LoadLibraryA is resolved out of kernel32
   113                              <1> ; (itself just another find_export call) and called to load-or-fetch the
   114                              <1> ; named module, then find_export resolves R8 inside *that* module's base.
   115                              <1> resolve_export:
   116 000000F3 4154                <1>     push r12        ; kernel32 base
   117 000000F5 4155                <1>     push r13        ; dll name ptr (or 0)
   118 000000F7 4156                <1>     push r14        ; func name ptr
   119 000000F9 55                  <1>     push rbp        ; stash pre-align rsp, same pattern as winexec_x64.asm's start
   120 000000FA 4889E5              <1>     mov rbp, rsp
   121 000000FD 4883E4F0            <1>     and rsp, ~0xF
   122                              <1> 
   123 00000101 4989CC              <1>     mov r12, rcx
   124 00000104 4989D5              <1>     mov r13, rdx
   125 00000107 4D89C6              <1>     mov r14, r8
   126                              <1> 
   127 0000010A 4D85ED              <1>     test r13, r13
   128 0000010D 750D                <1>     jnz .need_loadlibrary
   129                              <1> 
   130 0000010F 4C89E1              <1>     mov rcx, r12
   131 00000112 4C89F2              <1>     mov rdx, r14
   132 00000115 E850FFFFFF          <1>     call find_export
   133 0000011A EB36                <1>     jmp .resolve_done
   134                              <1> 
   135                              <1> .need_loadlibrary:
   136 0000011C 4C89E1              <1>     mov rcx, r12
   137 0000011F 488D1537000000      <1>     lea rdx, [rel name_loadlibrarya]
   138 00000126 E83FFFFFFF          <1>     call find_export
   139 0000012B 4885C0              <1>     test rax, rax
   140 0000012E 741F                <1>     jz .resolve_fail
   141                              <1> 
   142 00000130 4C89E9              <1>     mov rcx, r13        ; LoadLibraryA(lpLibFileName)
   143 00000133 4883EC20            <1>     sub rsp, 0x20       ; shadow space required before any WinAPI call
   144 00000137 FFD0                <1>     call rax
   145 00000139 4883C420            <1>     add rsp, 0x20
   146 0000013D 4885C0              <1>     test rax, rax
   147 00000140 740D                <1>     jz .resolve_fail
   148                              <1> 
   149 00000142 4889C1              <1>     mov rcx, rax        ; the newly (or already) loaded module's base
   150 00000145 4C89F2              <1>     mov rdx, r14
   151 00000148 E81DFFFFFF          <1>     call find_export
   152 0000014D EB03                <1>     jmp .resolve_done
   153                              <1> 
   154                              <1> .resolve_fail:
   155 0000014F 4831C0              <1>     xor rax, rax
   156                              <1> 
   157                              <1> .resolve_done:
   158 00000152 4889EC              <1>     mov rsp, rbp
   159 00000155 5D                  <1>     pop rbp
   160 00000156 415E                <1>     pop r14
   161 00000158 415D                <1>     pop r13
   162 0000015A 415C                <1>     pop r12
   163 0000015C C3                  <1>     ret
   164                              <1> 
   165 0000015D 4C6F61644C69627261- <1> name_loadlibrarya: db "LoadLibraryA", 0
   165 00000166 72794100            <1>
    40                                  
    41 0000016A 7573657233322E646C-     name_user32: db "user32.dll", 0
    41 00000173 6C00               
    42 00000175 4D657373616765426F-     name_messageboxa: db "MessageBoxA", 0
    42 0000017E 784100             
    43                                  
    44 00000181 90<rep 7h>              align 8
    45                                  text_buf:
    46 00000188 00<rep 100h>                times 256 db 0
    47                                  
    48                                  align 8
    49                                  caption_buf:
    50 00000288 00<rep 40h>                 times 64 db 0
