WineでMacのシステムコールを呼んでみる!
MacやLinuxでexeファイルが実行できるWineは"Emulator"ではなく"Compatibility Layer"。つまり、WindowsをMacの中で動かしているのではなく、exeから呼び出されるdllをMac用の物に置き換えることでexeを動かしている。
普通は、windowsアプリのシステムコール(ウィンドウ表示、ファイル書き込みなどの動作)はdllを仲介して呼び出されているため、dllをすげ替えればほとんどのexeは動く。
でも実は直接、dllを介さずにシステムコールを呼ぶこともできる。 そんなことをしたら一体どうなるのだろうか・・・?
ということで、Wine上にウィンドウ表示するとともに、Mac OSにシステムコールを直接叩きつけるという闇exeを作ってみた!
なんと、Wineでダイアログが表示されると同時に、ちゃんと標準出力にもメッセージが出てきた!
Assembly Code (MASM)
.386
.model flat, stdcall
option casemap:none
include libs\windows.inc
include libs\kernel32.inc
includelib libs\kernel32.lib
include libs\user32.inc
includelib libs\user32.lib
.data
MsgCaption db "Waiwai",0
MsgBoxText db "GayagayaGayagaya",0
Filename db "/Users/aidatorajiro/test",0
.code
start:
push ebp
mov ebp, esp
push sizeof MsgBoxText
push offset MsgBoxText
push 1
mov eax, 4
sub esp, 4
int 80h
add esp, 16
pop ebp
invoke MessageBox, NULL, addr MsgBoxText, addr MsgCaption, MB_OK
invoke ExitProcess, NULL
end start
これを応用して、色々作ってみる。
wine safari.exe
とするとSafariを起動する
Assembly Code (NASM)
global _main
extern _MessageBoxA@16
extern _ExitProcess@4
section .text
_main:
push 0
push message
push message
push 0
call _MessageBoxA@16
push ebp
mov ebp, esp
push 0
push argv
push app_path
mov eax, 59
sub esp, 4
int 80h
add esp, 16
pop ebp
push 0
call _ExitProcess@4
hlt
message:
db 'Hello, Black Magic World!', 0
message_end:
app_path:
db '/Applications/Safari.app/Contents/MacOS/Safari', 0
app_path_end:
argv:
dd app_path
dd 0
argv_end:
↓
数をかぞえあげるだけ。エントロピーもゲットできる。
左したがエントロピー(システムコールを呼ぶとコンピュータがくれるランダムな数字)。 右上のカウントをクリックするとカウントが上がっていく。
GUIを作るの、めちゃくちゃめんどくさい。。。
Assembly Code (NASM)
global _main
extern _MessageBoxA@16
extern _CreateWindowExA@48
extern _ExitProcess@4
extern _ShowWindow@8
extern _UpdateWindow@4
extern _GetLastError@0
extern _GetMessageA@16
extern _TranslateMessage@4
extern _DispatchMessageA@4
extern _RegisterClassExA@4
extern _DefWindowProcA@16
extern _LoadIconA@8
extern _LoadCursorA@8
extern _GetWindowLongA@8
extern _CreateWindowExA@48
extern _DestroyWindow@4
SYS_fork equ 2
SYS_execve equ 59
SYS_getentropy equ 500
section .data
winmsg:
times 7 dd 0
divisor_table:
dd 1000000000
dd 100000000
dd 10000000
dd 1000000
dd 100000
dd 10000
dd 1000
dd 100
dd 10
dd 1
dd 0
temp_str:
times 11 db 0
db 10
temp_args:
.hwin:
dd 0
.mess:
dd 0
.wpar:
dd 0
.lpar:
dd 0
count_int:
dd 0
window_long:
dd 0
handle_window:
dd 0
handle_button:
dd 0
win_instance:
dd 0
window_class:
db 'BLACKMAGICK', 0
window_name:
db 'うぃんどう', 0
message:
db 'Hello, Black Magic World!', 0
message_ari:
db 'ありだよ', 0
message_dame:
db 'なしだよ', 0
btn_class:
db 'BUTTON', 0
static_class:
db 'STATIC', 0
safari_text:
db 'さふぁり', 0
safari_id equ 152
exit_text:
db 'おわる', 0
exit_id equ 153
count_text:
db 'かうんと'
count_text_num:
db '0000000000'
db 0
count_id equ 154
count_handle:
dd 0
count_text_handle:
dd 0
entropy_btn_text:
db 'えんとろぴい', 0
entropy_num_int:
dd 0
entropy_num_text:
db '0000000000'
db 0
entropy_num_handle:
dd 0
entropy_id equ 155
app_path:
db '/Applications/Safari.app/Contents/MacOS/Safari', 0
app_argv:
dd app_path
dd 0
window_class_data:
dd (12*4) ; size
dd 3 ; style
dd func_win_callback ; proc
dd 0
dd 0
.instance:
dd 0 ; instance
.icon:
dd 0 ; icon
.cursor:
dd 0 ; cursor
dd (0 + 1) ; background
dd 0 ; menuname
dd window_class ; classname
dd 0 ; icon
section .text
_main:
; | |
; | INITialization |
; | |
mov eax, [esp + 4]
mov [win_instance], eax
push 0
push message
push message
push 0
call _MessageBoxA@16
mov eax, [win_instance]
mov [window_class_data.instance], eax
push 32512; IDI_APPLICATION
push 0
call _LoadIconA@8
mov [window_class_data.icon], eax
push 32514; IDC_ARROW + 2
push 0
call _LoadCursorA@8
mov [window_class_data.cursor], eax
push window_class_data
call _RegisterClassExA@4
push 0 ; param
mov eax, [win_instance]
push eax ; instance
push 0 ; menu
push 0 ; parent
push 600 ; h
push 1000 ; w
push 0x80000000 ; y
push 0x80000000 ; x
push 0x10000000 ; style
push window_name
push window_class
push 0 ; exstyle
call _CreateWindowExA@48
mov [handle_window], eax
call func_err_test
; | |
; | infinite loop |
; | |
infinite:
xor eax, eax
push 0
push 0
push dword [handle_window]
push winmsg
call _GetMessageA@16
cmp eax, 0 ; terminate
je infinite_exit
cmp eax, -1 ; error
je infinite_exit
push winmsg
call _TranslateMessage@4
push winmsg
call _DispatchMessageA@4
jmp infinite
infinite_exit:
push 0
call _ExitProcess@4
hlt
; | |
; | Windows callback function |
; | |
func_win_callback: ; handle, message, param, lparam
mov eax, [esp + 4]
mov [temp_args.hwin], eax ; hwin
mov eax, [esp + 8]
mov [temp_args.mess], eax ; mess
mov eax, [esp + 12]
mov [temp_args.wpar], eax ; wpar
mov eax, [esp + 16]
mov [temp_args.lpar], eax ; lpar
; | |
; | CREATE |
; | |
cmp dword [temp_args.mess], 1 ; if create
je .cond_m1
jmp .cond_m1_r
.cond_m1:
; get window long
push -6
push dword [temp_args.hwin]
call _GetWindowLongA@8
mov [window_long], eax
; create safari buttton
push 0
push dword [window_long]
push safari_id
push dword [temp_args.hwin]
push 30
push 100
push 10
push 10
push 0x50000000
push safari_text
push btn_class
push 0
call _CreateWindowExA@48
; create exit buttton
push 0
push dword [window_long]
push exit_id
push dword [temp_args.hwin]
push 30
push 100
push 90
push 80
push 0x50000000
push exit_text
push btn_class
push 0
call _CreateWindowExA@48
; create entropy buttton
push 0
push dword [window_long]
push entropy_id
push dword [temp_args.hwin]
push 30
push 100
push 400
push 30
push 0x50000000
push entropy_btn_text
push btn_class
push 0
call _CreateWindowExA@48
; create entropy text
call func_regenerate_entropy
; create count text & button
call func_redraw_count_btn
.cond_m1_r:
; | |
; | COMMAND |
; | |
cmp dword [temp_args.mess], 0x111 ; if command
je .cond_m2
jmp .cond_m2_r
.cond_m2:
; exit button pressed
cmp word [temp_args.wpar], exit_id ; if exit_id
je .flag_exit
jmp .flag_not_exit
.flag_exit:
push dword [temp_args.hwin]
call _DestroyWindow@4
mov eax, 0
ret
.flag_not_exit:
; safari button pressed
cmp word [temp_args.wpar], safari_id ; if safari_id
je .flag_safari
jmp .flag_not_safari
.flag_safari:
push ebp
mov ebp, esp
push 0
push app_argv
push app_path
mov eax, SYS_fork
sub esp, 4
int 80h
add esp, 16
pop ebp
cmp edx, 0
je .parent
jmp .child
.child:
push ebp
mov ebp, esp
push 0
push app_argv
push app_path
mov eax, SYS_execve
sub esp, 4
int 80h
add esp, 16
pop ebp
.parent:
.flag_not_safari:
; count button pressed
cmp word [temp_args.wpar], count_id ; if count_id
je .flag_count
jmp .flag_not_count
.flag_count:
add dword [count_int], 1
mov eax, [count_int]
mov ebx, count_text_num
call func_int_to_str
call func_redraw_count_btn
.flag_not_count:
; entropy button pressed
cmp word [temp_args.wpar], entropy_id ; if count_id
je .flag_entropy
jmp .flag_not_entropy
.flag_entropy:
call func_regenerate_entropy
.flag_not_entropy:
.cond_m2_r:
; | |
; | DEFAULT |
; | |
push dword [temp_args.lpar]
push dword [temp_args.wpar]
push dword [temp_args.mess]
push dword [temp_args.hwin]
call _DefWindowProcA@16
ret
; | |
; | misc functions |
; | |
; redraw entropy text
func_regenerate_entropy:
cmp dword [entropy_num_handle],0
je .create
jmp .del
.del:
push dword [entropy_num_handle]
call _DestroyWindow@4
.create:
push ebp
mov ebp, esp
push 4
push entropy_num_int
mov eax, SYS_getentropy
sub esp, 4
int 80h
add esp, 12
pop ebp
mov eax, [entropy_num_int]
mov ebx, entropy_num_text
call func_int_to_str
push 0
push dword [window_long]
push 0
push dword [temp_args.hwin]
push 30
push 100
push 450
push 30
push 0x50000000
push entropy_num_text
push static_class
push 0
call _CreateWindowExA@48
mov [entropy_num_handle], eax
; redraw count button and text
func_redraw_count_btn:
cmp dword [count_handle],0
je .create
jmp .del
.del:
push dword [count_handle]
call _DestroyWindow@4
push dword [count_text_handle]
call _DestroyWindow@4
.create:
push 0
push dword [window_long]
push count_id
push dword [temp_args.hwin]
push 30
push 200
push 180
push 480
push 0x50000000
push count_text
push btn_class
push 0
call _CreateWindowExA@48
mov [count_handle], eax
push 0
push dword [window_long]
push 0
push dword [temp_args.hwin]
push 30
push 200
push 300
push 300
push 0x50000000
push count_text_num
push static_class
push 0
call _CreateWindowExA@48
mov [count_text_handle], eax
ret
; print current error via MessageBox
func_print_err:
push eax
push ebx
call _GetLastError@0
mov ebx, temp_str
call func_int_to_str
push 0
push message_dame
push temp_str
push 0
call _MessageBoxA@16
pop ebx
pop eax
ret
; chack if handle exists and print debug info via MessageBox
func_err_test: ; eax = handle
cmp eax, 0
je cond_whnd_t
jmp cond_whnd_f
cond_whnd_t:
call func_print_err
jmp cond_whnd_r
cond_whnd_f:
push 0
push message_ari
push message_ari
push 0
call _MessageBoxA@16
jmp cond_whnd_r
cond_whnd_r:
ret
; int to str
func_int_to_str: ; eax = number, ebx = pointer to string
push eax
push ebx
push ecx
push edx
mov ecx, ebx
mov ebx,divisor_table
.loop:
xor edx,edx
div dword [ebx]
add eax,'0'
mov byte [ecx], al
mov eax,edx
add ecx,1
add ebx,4
cmp dword [ebx],0
jne .loop
pop edx
pop ecx
pop ebx
pop eax
ret
さいごに
MacOS 10.15のリリースに伴い、32-bitのexeはWineでは実行できなくなってしまいました。。 さようなら、Wine….