Δευτέρα 14 Σεπτεμβρίου 2026

Assembly x86 Create Exe with icon, manifest, version info

 




ASM2 (just write EDIT ASM2 and paste the code)

function versionInfo(v1, v2) {
Function global Padding(address) {
a=address mod 4
if a=0 then =a else =4-a
}
function fix(v1, v2) {
structure FIXEDFILEINFO {
dwSignature as Long
{ minor as Integer,
major as Integer
}
dwStrucVersion as Long
dwFileVersionMSlow as Integer
dwFileVersionMShigh as Integer
dwFileVersionLS as Long
dwProductVersionMSlow as Integer
dwProductVersionMShigh as Integer

dwProductVersionLS as Long
dwFileFlagsMask as Long
dwFileFlags as Long
dwFileOS as Long
dwFileType as Long
dwFileSubtype as Long
dwFileDateMS as Long
dwFileDateLS as Long
function init (v1, v2){
const VOS__WINDOWS32=4, VFT_APP=1
FIXEDFILEINFO|dwSignature=0xFEEF04BD
FIXEDFILEINFO|major=1
FIXEDFILEINFO|minor=0
FIXEDFILEINFO|dwFileVersionMShigh=1
FIXEDFILEINFO|dwProductVersionMShigh=v1
FIXEDFILEINFO|dwProductVersionMSlow=v2
FIXEDFILEINFO|dwFileOS=VOS__WINDOWS32
FIXEDFILEINFO|dwFileType=VFT_APP
structure myDate {
{ low as long, high as long}
mydate as double
}
myDate ThisDate
ThisDate|mydate=today+now
FIXEDFILEINFO|dwFileDateMS=ThisDate|high
FIXEDFILEINFO|dwFileDateLS=ThisDate|low
=FIXEDFILEINFO
}
}
FIXEDFILEINFO fix#init(v1, v2)
=fix
}
ver.size=2000
addr=0
buffer clear ver as byte*ver.size
return ver, 2:=52 as Integer, 4:=0 as Integer
addr=6
ver[addr]="VS_VERSION_INFO"+chr$(0)
addr+=32
addr+=padding(addr)
ver[addr]=fix(v1,v2)
addr+=52
addr+=padding(addr)
block1=addr ' open sub block
' addr+2 =0 ' addr+4 =0  ' for VarFileInfo
addr+=6 ' 6 bytes header
ver[addr]="VarFileInfo"
addr+=24 ' 11*2+2
addr+=padding(addr)
block2=addr ' open sub block
ver[addr+2]=4 ' 4 word  ' addr+4 = 0  (type=0)
ver[addr+6]="Translation"
addr+=24+6 ' 11*2+2
addr+=padding(addr)
return ver, addr:= 0x409 as integer, addr+2:=1200 as integer
addr+=4
return ver, Block2:= addr-Block2 as integer ' close sub block
return ver, Block1:= addr-Block1 as integer ' close sub block

block2=addr ' open sub block
ver[addr+4]=1 ' type text  ' addr+2 = 0  (length value=0)
ver[addr+6]="StringFileInfo"
addr+=30+6 ' 11*2+2
addr+=padding(addr)
block3=addr ' open sub block

ver[addr+4]=1 ' type text  ' addr+2 = 0  (length value=0)
ver[addr+6]="040904B0"
addr+=16+8
addr+=padding(addr)
old=addr
AddString(&addr, ver, "Comments", "Example")
AddString(&addr, ver, "CompanyName","George's Software House")
AddString(&addr, ver, "FileDescription", "M2000 Native Win32 Window Application")
AddString(&addr, ver, "FileVersion", "1.0.0.0")
AddString(&addr, ver, "InternalName", "testAsm3.exe")
AddString(&addr, ver, "LegalCopyright", "Copyright (C) 2026 George")
AddString(&addr, ver, "OriginalFilename", "testAsm3.exe")
AddString(&addr, ver, "ProductName", "M2000 Assembly Window Project")
AddString(&addr, ver, "ProductVersion", v1+"."+v2+".0.0")
return ver, Block3:= addr-Block3 as integer ' close sub block
return ver, Block2:= addr-Block2 as integer ' close sub block
return ver, 0:=addr as integer
buffer ver as byte*addr ' redim and preserve bytes
=ver
sub AddString(&w, buf, v1 as string, v2 as string)
v1+=chr(0)
v2+=chr(0)
local block=w
return buf, w+2:=len(v2)*2 as integer, w+4:=1 as integer
w+=6:buf[w]=v1: w+=len(v1)*2
w+=padding(w)
buf[w]=v2: w+=len(v2)*2
return buf, block:=w-block as integer
w+=padding(w)
end sub
}
Binary {
      AAABAAMAICAQAAAAAADoAgAANgAAACAgAgAAAAAAMAEAAB4DAAAQEBAAAAAAACgB
      AABOBAAAKAAAACAAAABAAAAAAQAEAAAAAACAAgAAAAAAAAAAAAAAAAAAAAAAAAAA
      AAAAAIAAAIAAAACAgACAAAAAgACAAICAAADAwMAAgICAAAAA/wAA/wAAAP//AP8A
      AAD/AP8A//8AAP///wAAAAAAAAAAD/////////8AAAAAAAAAAP//////////8AAA
      AAAAAA/8zMzMzMzMzP8AAAAAAAAPzMzM///3fMzPAA////8AD8zMz/d3d3zMzwDx
      ERER8A/MzP93zMfMzM8PGZmZkRAPzM/3zMzMzMzPD5mZmZkfD8z/fMzMzMzMzw+Z
      mZmZH//M93zMzM/8fM8PmZmZmRKvzHfMzMzH/MfPD5mZmZkSL8x8zMzMzMx3zw+f
      +ZmZEq/MfMzMzMzHfM8Pn/mZmRIvzMfM/8zMzMzPD5/5mZkSr8zMzH/HzMzMzw+f
      +ZmZEq/MzMfMd8zMzM8Pn/mZmRIvzMzHd3fMzMzPD5mZmZkSr/zMzMzMzMzM/w+Z
      mZmZEiL///////////APEZkRERKiqiqiKiqqL/AAD7N5u7syqqoqKqqiqi8AAA+z
      d7u7MiIiIiIiIiIvAAAPOZu7uzKiqqqqoqKqLwAADzebu7syIiIiIiIiIi8AAA83
      e7u7MqqiqiqqqqovAAAPmbu7uzIiIiIiIiIiLwAAD3m7u7syqioqqqIqIq8AAA93
      +7u7MiIiIiIiIiIvAAD5n/+7uzMzMz///////wAA958P/7u7u7v/AAAAAAAAAPd/
      AA//+7//8AAAAAAAAAD//wAAAP//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//
      //////////4AA//8AAH//AAB4DwAAcAcAAHAHAABwBwAAcAEAAHABAABwAQAAcAE
      AAHABAABwAQAAcAEAAHABgADwAP//8AAAB/AAAAfwAAAH8AAAB/AAAAfwAAAH8AA
      AB/AAAAfyAAAH5wAf/+fAP//n+f/////////////KAAAACAAAABAAAAAAQABAAAA
      AAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8AAAH//AAD//4ABgADAAQPgR/E
      GAEvpDABQMRgAUB0wAFAPIBpQCQAKUAkAAlYJAABWCQMAVgkBAFYJAABWCQHAUA0
      AANAaAACc9VVWEoKqrBOEFBQRAiosFQVVVBcCqqwSBEREHgKqrB4FVVQnAB/8PcA
      wADx54AA8DwAAAAAAAD////////////+AAP//AAB//wAAeA8AAHAHAABwBwAAcAc
      AAHABAABwAQAAcAEAAHABAABwAQAAcAEAAHABAABwAAAA8AAAAPAAAAfwAAAH8AA
      AB/AAAAfwAAAH8AAAB/AAAAfwAAAH8gAAB+MAH//jwD//5/n/////////////ygA
      AAAQAAAAIAAAAAEABAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACA
      AAAAgIAAgAAAAIAAgACAgAAAwMDAAICAgAAAAP8AAP8AAAD//wD/AAAA/wD/AP//
      AAD///8AAAAAD/////AP///8zMzMz/EREfzP//zP+ZmR/P/M/8/5mZH8zMzMz/+Z
      kfzMzMzP/5mR/P/M/8//mZH393z3f/mZkfzMzMzP8XERL/////D/m7sqoqKi8Peb
      uyIiIiLw93u7KqKqovB5e7siIiIi8Hn/+7u////wdwD///8AAAD//wAA/gEAAIIB
      AACCAQAAggEAAIIBAACCAQAAggEAAIIBAACB/wAAwAMAAIADAACAAwAAAAMAADh/
      AAA//wAA
} As buffer1


icoCount= Eval(buffer1, 4 as Integer)


Buffer grpIconData as Byte*(6 + (icoCount * 14))
grpIconData[0] = buffer1[0, 6]
Assembler =getobject("","m2000.x86")
Assembler=>ClearResources


ver=versionInfo(1,1)
Assembler=>AddRawResource 16, 1, ver(0), len(ver)


buffer targetID as integer
For i = 0 to icoCount - 1
    entryOffset = 6 + (i * 16) ' Each ICO entry in file is 16 bytes
    targetID[0] = i + 1 ' We link each image to a sequential Resource ID (1, 2, 3...)

    ' Extract width, height, colors, planes, bitcount and size from the file entry (first 12 bytes)
    grpIconData[6 + (i * 14)] = buffer1[entryOffset, 12]
    ' Write the Target Resource ID into the group descriptor (last 2 bytes of GRPICONDIRENTRY)
    grpIconData[6 + (i * 14) + 12]=targetID

    ' Extract layout markers to pull the raw bitmap bytes
    bytesInRes = Eval(buffer1, entryOffset + 8 as long) ' dwBytesInRes
    imageOffset = Eval(buffer1, entryOffset + 12 as long) ' dwImageOffset

    ' 3. Extract the pure raw bitmap stream for this specific resolution
    'Buffer rawBitmap as Byte*bytesInRes
    'rawBitmap = buffer1[imageOffset, bytesInRes]

    ' Register this raw image slice as Type 3 (RT_ICON) with its unique ID
    Assembler=>AddRawResource 3, targetID[0], buffer1(imageOffset), bytesInRes
Next


' 4. Register the full compiled group header as Type 14 (RT_GROUP_ICON), ID 1
Assembler=>AddRawResource 14, 1, grpIconData(0), Len(grpIconData)


' Inject the Application Manifest XML String (Type 24 = Manifest, ID = 1)
manifest$ = {<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <dependency>
    <dependentAssembly>
      
    </dependentAssembly>
  </dependency>
</assembly>}


Buffer manifestData as Byte*Len(manifest$)
manifestData[0]=STR$(manifest$) ' UTF16LE TO ANSI


Static Function MachineCode
SplitHor(7/10)
Enum PESubsystem {
    Subsystem_GUI = 2
    Subsystem_CUI = 3
}
'''''''''''Assembler=>AddRawResource 3, 1, buffer1(0), Len(buffer1)
// buffer clear emptybuffer as byte*4096
// Assembler=>AddRawResource 21, 1, emptybuffer(0), 4096
Assembler=>AddRawResource 24, 1, manifestData(0), Len(manifestData)
Assembler=>Subsystem=Subsystem_GUI
Assembler=>PEHeader=true
long WM_SETTEXT = &HC
// use DW to place the unicode string
WindowTitleCaption="成长汉 - Γιώργος - M2000 Asm: "+today+" "+now
AppNameL="ASM Window"
Buffer2export=MachineCode({
extern "kernel32", GetModuleHandleA
extern "user32",   LoadCursorA
extern "user32",   RegisterClassW
extern "user32",   UnregisterClassW
extern "user32",   CreateWindowExW


extern "user32",   DestroyWindow
extern "user32",   ShowWindow
extern "user32",   GetMessageW
extern "user32",   TranslateMessage
extern "user32",   DispatchMessageW
extern "user32",   DefWindowProcW
extern "user32",   PostQuitMessage
extern "user32",   LoadIconW


AppName:           dW AppNameL, 0   ; use dw for unicode strings
WindowTitle:       dW WindowTitleCaption, 0
hInstance:         dd 0
hCursor:           dd 0
hWnd:              dd 0
wMsg:              dd 0


COLOR_APPWORKSPACE equ 12
SIZEOF_WNDCLASS    equ 40
SIZEOF_MSG         equ 28
WM_DESTROY         equ &H2
IDC_ARROW          equ &H7F00


main:
   push ebp
   mov  ebp, esp


   push dword 0
   call GetModuleHandleA
   mov [hInstance], eax


   push dword IDC_ARROW
   push dword 0
   call LoadCursorA
   mov [hCursor], eax


   ;;;;;; WND CLASS ;;;;;;;;


   sub esp, SIZEOF_WNDCLASS                ; WNDCLASS 40 Bytes
   
   mov dword [esp+0], 3                    ; style = CS_HREDRAW or CS_VREDRAW
   mov dword [esp+4], WndProc              ; lpfnWndProc = WndProc
   mov dword [esp+8], 0                    ; cbClsExtra = 0
   mov dword [esp+12], 0                   ; cbWndExtra = 0


   mov eax, [hInstance]
   mov dword [esp+16], eax                 ; hInstance


   ; --- Load Icon from Resources ID = 1 ---
   push dword 1                            ; Resource ID = 1
   push dword [hInstance]                  ; hInstance
   call LoadIconW                          ; Returns hIcon in EAX
   mov dword [esp+20], eax                 ; Set hIcon = EAX

   mov eax, [hCursor]
   mov dword [esp+24], eax                 ; hCursor


   mov dword [esp+28], COLOR_APPWORKSPACE  ; background color
   mov dword [esp+32], 0                   ; lpzszMenuName = 0
   mov dword [esp+36], AppName             ; lpszClassName = AppName


   mov eax, esp
   push eax                                ; register the window class
   call RegisterClassW


   ;;;;;; CREATEWINDOW ;;;;;;;;


   push dword 0                            ; lParam
   push dword [hInstance]                  ; hInstance
   push dword 0                            ; hMenu
   push dword 0                            ; hWndParent
   push dword 250                          ; Height
   push dword 480                          ; Width
   push dword 0                            ; y
   push dword 0                            ; x
   push dword &HCF0000                     ; WS_OVERLAPPEDWND or WS_BORDER or WS_CAPTION
   push dword WindowTitle                  ; lpWindowName
   push dword AppName                      ; ClassName
   push dword &H40000                      ; dwExStyle
   call CreateWindowExW


   mov [hWnd], eax


   push dword 1                            ; show the window
   push dword [hWnd]
   call ShowWindow


   ;;;;;; MESSAGELOOP ;;;;;;;;


   sub  esp, SIZEOF_MSG                    ; space for MSG Struct
   mov  [wMsg], esp
   align 4
   MessageLoop:
       push dword 0                        ; get a message from the queue
       push dword 0
       push dword 0
       push dword [wMsg]
       call GetMessageW


       test eax, eax
       jz   ExitMessageLoop


       push dword [wMsg]                   ; process the message
       call TranslateMessage
       push dword [wMsg]
       call DispatchMessageW


       jmp  MessageLoop


   ExitMessageLoop:
   add  esp, SIZEOF_MSG                    ; Καθαρισμός MSG struct (28 bytes)


   push dword [hWnd]                       ; destroy the window
   call DestroyWindow


   push dword [hInstance]                  ; unregister the window class
   push dword AppName
   call UnregisterClassW


   add  esp, SIZEOF_WNDCLASS               ; Καθαρισμός WNDCLASS Struct (40 bytes)
   
   pop  ebp                                ; Αποκατάσταση ebp
   ret                                     ; Καθαρή επιστροφή στη M2000


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;; WndProc Διορθωμένη ;;;;;;;;;;


WndProc:
   mov  eax, [esp+8]                       ; Message
   cmp  eax, WM_DESTROY                    ; WM_DESTROY;
   jne  WndProcNext                        ; No goto DefWindowProcW
   
   ; Διαχείριση WM_DESTROY
   push dword 0
   call PostQuitMessage
   
   xor  eax, eax                           ; Return 0 (επιτυχία)
   ret  16                                 ; Έξοδος από τη WndProc χωρίς DefWindowProcW


WndProcNext:
   push dword [esp+16]                     
   push dword [esp+16]
   push dword [esp+16]
   push dword [esp+16]
   call DefWindowProcW


   ret 16


})
killit()
open "testAsm3.exe" for output as #f
put #f, Buffer2export
close #f
// Declare ShellExecute Lib "shell32.ShellExecuteW" {Long hWnd, Long lpszOp, lpszFile$, long lpszParams, long LpszDir, Long FsShowCmd }
// Print ShellExecute(0, 0, dir$+"testAsm3.exe", 0, 0, 1&)
//
win dir$+"testAsm3.exe"
if module(asm22) then asm22
Sub killit(name$="testAsm3.exe")
local out$=quote$(dir$+"out.txt")
Dos "del "+out$, 500;
name$=lcase(name$)
Dos format({tasklist /fi "IMAGENAME eq {0}" >}+out$, name$), 500;
local a$
document a$
load.doc a$,"out.txt"
local m=Paragraph(a$, 0)
If Forward(a$,m) then
While m
p=Paragraph$(a$,(m))
if lcase(left(p, len(name$)))=name$ then
Pid=val(trim(rightpart(p, " ")))
Dos "taskkill /F /PID "+pid;
Print "Pid=";Pid;" ...killed in action"
End if
End While
End If
End Sub
Function MachineCode(assembly as string)
if Assembler=>assemble(assembly, true) then
local OutPutSize=Assembler=>OutputSize
local mc
buffer code mc as byte*OutputSize
' feed the base address to Assembler
Assembler=>BaseAddress=&H400000
if Assembler=>assemble(assembly) then
' get a copy of final machine code
mc=>FillDataFromMem Assembler=>GetOutPtr
=mc
exit function
End if
End if
error Assembler=>LastErrorMessage
End Function
Sub SplitHor(ratio as single)
if ratio<0.15 or ratio>0.85 then ratio=0.5
local old=mode
window 6, window
back {
local x1=scale.x,y1=scale.y
x=scale.x*ratio:window 6, x, y1
}
mode old, x, y1
back {motion x1-scale.x, (y1-scale.y)/2}
end sub


ASM22 module (just write EDIT ASM22 and paste the code)

module OtherWay (file$){
Print "SECOND WAY"
thatDir$=file.path$(file$)
thatFile$=file.name$(file$)
if thatDir$="" then Error "I Need Path"
FSO = GetObject("","Scripting.FileSystemObject")
objShell = GetObject("","Shell.Application")
objFolder = objShell=>Namespace(thatDir$)^ // ret object
objFolderItem = objFolder=>ParseName(thatFile$)^ // ret object
for i=1 to 40
zz= objFolder=>GetDetailsOf(objFolder=>Items, i)
if zz="" then exit for
if len(objFolder=>GetDetailsOf(objFolderItem, i))>0 then
Print zz, @(30), " : "; objFolder=>GetDetailsOf(objFolderItem, i)
end if
next
Print "THIRD WAY"
Print GetVersionInfo(file$, "ProductName")
Print GetVersionInfo(file$, "ProductVersion")


function GetVersionInfo(Path as string, id as string)
local shell, file
shell = GetObject("","Shell.Application")
local ssfDesktop = 0&
try ok {
file = shell=>Namespace(ssfDesktop)=>ParseName(Path)^
}
if ok then
=id+" : "+file=>ExtendedProperty("System.Software."+id)
else
="<???>"
end if
end function


}


structure FIXEDFILEINFO {
dwSignature as Long
{ minor as Integer,
major as Integer
}
dwStrucVersion as Long
dwFileVersionMSlow as Integer
dwFileVersionMShigh as Integer
dwFileVersionLS as Long
{
dwProductVersionMSlow as Integer,
dwProductVersionMShigh as Integer
}  ' union
dwProductVersionMS as long

{dwProductVersionLSlow as Integer,
dwProductVersionLSHigh as Integer
} ' union
dwProductVersionLS as Long

dwFileFlagsMask as Long
dwFileFlags as Long
dwFileOS as Long
dwFileType as Long
dwFileSubtype as Long
dwFileDateMS as Long
dwFileDateLS as Long
function init (v1, v2){
const VOS__WINDOWS32=4, VFT_APP=1
FIXEDFILEINFO|dwSignature=0xFEEF04BD
FIXEDFILEINFO|major=1
FIXEDFILEINFO|minor=0
FIXEDFILEINFO|dwFileVersionMShigh=1
FIXEDFILEINFO|dwProductVersionMShigh=v1
FIXEDFILEINFO|dwProductVersionMSlow=v2
FIXEDFILEINFO|dwFileOS=VOS__WINDOWS32
FIXEDFILEINFO|dwFileType=VFT_APP
structure myDate {
{ low as long, high as long}
mydate as double
}
myDate ThisDate
ThisDate|mydate=today+now
FIXEDFILEINFO|dwFileDateMS=ThisDate|high
FIXEDFILEINFO|dwFileDateLS=ThisDate|low
=FIXEDFILEINFO
}
}


file$=dir$+"testAsm3.exe"
if exist(file$) then
Declare GetFileVersionInfoSize lib "Api-ms-win-core-version-l1-1-0.GetFileVersionInfoSizeW" {lptstrFilename$, long &handle} as long
long that
long zz=GetFileVersionInfoSize(file$, &that)
Declare GetFileVersionInfo lib "Api-ms-win-core-version-l1-1-0.GetFileVersionInfoW" {lptstrFilename$, long Zero, long dwLen, long buffer1} as integer
buffer VersionInfo as byte *zz
boolean ret=GetFileVersionInfo(file$, 0&, zz, VersionInfo(0))
if ret then
declare VerQueryValue lib "Api-ms-win-core-version-l1-1-0.VerQueryValueW" {long pblock, SubBloc$, long &lVerPointer, long &lVerbufferLen } as integer
long p, blen
If VerQueryValue(VersionInfo(0), "\", &p, &bLen) then
// ?  p, blen
FIXEDFILEINFO fix
if blen=len(fix) then
fix=>FillDataFromMem p
' press F1 in Editor to tongle wrap
print "ProductVersion = ";fix|dwProductVersionMShigh+"."+fix|dwProductVersionMSlow+"."+fix|dwProductVersionLShigh+"."+fix|dwProductVersionLSlow
end if
else
? "failed"
end if
If VerQueryValue(VersionInfo(0), "\StringFileInfo\040904b0\CompanyName", &p, &bLen) then
buffer strRet as byte * blen
strRet=>FillDataFromMem p
Print "CompanyName : ";leftpart(eval$(strRet), 0)
else
? "failed"
end if
else
? "????"
end if


OtherWay file$
' another way...

end if
//clipboard string$(eval$(VersionInfo) as encode64, 0, 6) ' send  BASE64 encoded to clipboard





Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου

You can feel free to write any suggestion, or idea on the subject.