HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2018
0101
雪月夜マシン語の作り方6解決


雪月夜

リンク

2018/1/1(Mon) 17:46:35|NO.82152

あけましておめでとうございます

HSPのマシン語を作成しようとしたのですが、上手くいきません
作成手順は以下のサイトを参考にしました
http://chokuto.ifdef.jp/urawaza/mcn/vc_enumwnd.html

OSはWindows7の64bit版、開発環境はVisual Studio 2017 Communityです。
codファイルを出力した結果、中身は以下のようになりました


( 〜 省 略 〜 ) ; Line 4 00000 55 push ebp 00001 8b ec mov ebp, esp 00003 81 ec e8 00 00 00 sub esp, 232 ; 000000e8H 00009 53 push ebx 0000a 56 push esi 0000b 57 push edi 0000c 8d bd 18 ff ff ff lea edi, DWORD PTR [ebp-232] 00012 b9 3a 00 00 00 mov ecx, 58 ; 0000003aH 00017 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH 0001c f3 ab rep stosd ; Line 5 0001e c7 45 f8 11 11 11 11 mov DWORD PTR _p_hwnd$[ebp], 286331153 ; 11111111H ; Line 6 00025 c7 45 ec 22 22 22 22 mov DWORD PTR _p_cnt$[ebp], 572662306 ; 22222222H ; Line 7 0002c c7 45 e0 33 33 33 33 mov DWORD PTR _max_num$[ebp], 858993459 ; 33333333H ; Line 9 00033 8b 45 ec mov eax, DWORD PTR _p_cnt$[ebp] 00036 8b 4d e0 mov ecx, DWORD PTR _max_num$[ebp] 00039 39 08 cmp DWORD PTR [eax], ecx 0003b 7c 04 jl SHORT $LN2@EnumWindow ; Line 10 0003d 33 c0 xor eax, eax 0003f eb 32 jmp SHORT $LN1@EnumWindow $LN2@EnumWindow: ; Line 11 00041 8b 45 ec mov eax, DWORD PTR _p_cnt$[ebp] 00044 8b 08 mov ecx, DWORD PTR [eax] 00046 c1 e1 02 shl ecx, 2 00049 8b 55 f8 mov edx, DWORD PTR _p_hwnd$[ebp] 0004c 8b 45 08 mov eax, DWORD PTR _hwnd$[ebp] 0004f 89 04 0a mov DWORD PTR [edx+ecx], eax ; Line 12 00052 8b 45 ec mov eax, DWORD PTR _p_cnt$[ebp] 00055 89 85 18 ff ff ff mov DWORD PTR tv71[ebp], eax 0005b 8b 8d 18 ff ff ff mov ecx, DWORD PTR tv71[ebp] 00061 8b 11 mov edx, DWORD PTR [ecx] 00063 83 c2 01 add edx, 1 00066 8b 85 18 ff ff ff mov eax, DWORD PTR tv71[ebp] 0006c 89 10 mov DWORD PTR [eax], edx ; Line 13 0006e b8 01 00 00 00 mov eax, 1 $LN1@EnumWindow: ; Line 14 00073 5f pop edi 00074 5e pop esi 00075 5b pop ebx 00076 8b e5 mov esp, ebp 00078 5d pop ebp 00079 c2 08 00 ret 8 _EnumWindowsProc@8 ENDP _TEXT ENDS END
↓は参考サイトを元に変換したマシン語コード

fncode.0=$81ec8b55,$0000e8ec,$57565300,$ff18bd8d,$3ab9ffff,$b8000000 fncode.6=$cccccccc,$45c7abf3,$111111f8,$ec45c711,$22222222,$33e045c7 fncode.12=$8b333333,$4d8bec45,$7c0839e0,$ebc03304,$ec458b32,$e1c1088b fncode.18=$f8558b02,$8908458b,$458b0a04,$188589ec,$8bffffff,$ffff188d fncode.24=$83118bff,$858b01c2,$ffffff18,$01b81089,$5f000000,$e58b5b5e fncode.30=$0008c25d

上記のマシン語をスクリプトに組み込み実行した結果、エラーが出てしまいました
HSPで正しく動作するマシン語が出力されるようにするには、どうすればよいのでしょうか?

ちなみに下は参考サイトに載っていたマシン語です
こちらは問題なく動作しました

fncode = $222222b8, $81088b22, $333333f9, $33057c33, $0008c2c0, $0424548b fncode.6 = $118d1489, $8b111111, $08894108, $000001b8, $0008c200

よろしくお願いします



この記事に返信する


あまら

リンク

2018/1/4(Thu) 15:03:53|NO.82160

HSP側のソースはどうしたのでしょうか?

ちょくとさんのはHSP2時代のソースなのでHSP3だと少々修正しないといけないんですよね。

一応HSP2.61で確認してみましたが、ちょくとさんの方はできましたが、
雪月夜さんのマシン語はエラーになるのは確認できました。
Cのソースもちょくとさんとものと同じですよね?

こちらはWindows10ですが、同じ開発環境でコンパイルしてみましたが雪月夜さんとは
微妙に違うものが出力されて……
さらにそちらもエラーでした。

Visual Studioって設定で出力されるマシン語が変わるので、
それでも前にマシン語使ってみた時は出来たんですが、当時のソースが行方不明……
且つマシン語が久しぶりすぎてどうやってたかすら忘れている始末……

デバッグだとマシン語が出力できるのにリリースだとヘッダ部分しか出力してくれないし……

ちょっと愚痴や言い訳が入ってしまいましたが、
コンパイラよりもHSP側のバージョンやソースを見せていただければ、
忘却状態の私よりも的確な回答して下さる方が出て来ると思いますよ。



雪月夜

リンク

2018/1/5(Fri) 00:50:58|NO.82169

あまらさん、返信ありがとうございます

>HSP側のソースはどうしたのでしょうか?

失礼しました
確認に用いたHSPのソースは以下になります

#include "llmod3/llmod3.hsp" #ifndef xdim #uselib "kernel32.dll" #func global VirtualProtect@_xdim "VirtualProtect" var,int,int,var #define global xdim(%1,%2) dim %1,%2: VirtualProtect@_xdim %1,%2*4,$40,x@_xdim #endif ; マシン語を変数に格納する (必ず xdim を使用すること) xdim fncode, 11 fncode = $222222b8, $81088b22, $333333f9, $33057c33, $0008c2c0, $0424548b fncode.6 = $118d1489, $8b111111, $08894108, $000001b8, $0008c200 ; マシン語コードのアドレス(コールバック関数アドレス)取得 getptr pfn, fncode ; カウンタ用変数のアドレスを1バイト目にセット getptr t, wndcnt memcpy fncode, t, 4, 1 ; 列挙するウィンドウの最大数(配列の要素数)を9バイト目にセット t = 256 memcpy fncode, t, 4, 9 ; ウィンドウハンドルを格納する配列変数のアドレスを$1bバイト目にセット dim ahwnd, 512 getptr t, ahwnd memcpy fncode, t, 4, $1b ; カウンタを 0 にセット wndcnt = 0 ; EnumWindows の呼び出し pm = pfn, 0 dllproc "EnumWindows", pm, 2, D_USER dialog "" + wndcnt + "個のウィンドウハンドルが取得されました。" stop
HSPのバージョンは最新版の3.5です
参考サイトそのままでは実行できなかったので一部修正しました

>Cのソースもちょくとさんとものと同じですよね?

はい、サイトの「ソースファイル enumwnd.c」とまったく同じです


後で分かったんですが、確かにDebugとReleaseでは出力結果が異りますね
最初に投稿したのはデバックの方で、リリースだと以下のようになりました

; Line 4 00000 55 push ebp 00001 8b ec mov ebp, esp 00003 83 ec 0c sub esp, 12 ; 0000000cH ; Line 5 00006 c7 45 f4 11 11 11 11 mov DWORD PTR _p_hwnd$[ebp], 286331153 ; 11111111H ; Line 6 0000d c7 45 fc 22 22 22 22 mov DWORD PTR _p_cnt$[ebp], 572662306 ; 22222222H ; Line 7 00014 c7 45 f8 33 33 33 33 mov DWORD PTR _max_num$[ebp], 858993459 ; 33333333H ; Line 9 0001b 8b 4d f8 mov ecx, DWORD PTR _max_num$[ebp] 0001e 8b 45 fc mov eax, DWORD PTR _p_cnt$[ebp] 00021 39 08 cmp DWORD PTR [eax], ecx 00023 7c 08 jl SHORT $LN2@EnumWindow ; Line 10 00025 33 c0 xor eax, eax ; Line 14 00027 8b e5 mov esp, ebp 00029 5d pop ebp 0002a c2 08 00 ret 8 $LN2@EnumWindow: ; Line 11 0002d 8b 45 fc mov eax, DWORD PTR _p_cnt$[ebp] 00030 8b 4d f4 mov ecx, DWORD PTR _p_hwnd$[ebp] 00033 8b 10 mov edx, DWORD PTR [eax] 00035 8b 45 08 mov eax, DWORD PTR _hwnd$[ebp] 00038 89 04 91 mov DWORD PTR [ecx+edx*4], eax ; Line 12 0003b 8b 45 fc mov eax, DWORD PTR _p_cnt$[ebp] 0003e ff 00 inc DWORD PTR [eax] ; Line 13 00040 b8 01 00 00 00 mov eax, 1 ; Line 14 00045 8b e5 mov esp, ebp 00047 5d pop ebp 00048 c2 08 00 ret 8 _EnumWindowsProc@8 ENDP _TEXT ENDS END
ちなみにこちらの方もHSPではエラーになりました



雪月夜

リンク

2018/1/5(Fri) 01:10:30|NO.82170

あとリリースのマシン語は
メニューの「プロジェクト」>「〜のプロパティ」>構成プロパティ>C/C++>最適化
の「プログラム全体の最適化」を「いいえ」にすると出力されます

参考サイト
http://mag.autumn.org/Content.modf?id=20070905130712



あまら

リンク

2018/1/5(Fri) 01:50:13|NO.82171

少し思い出してきたので、試してみたら成功しました。

HSPのソースは雪月夜さんの物に少し手を加えさせていただきました。
マシン語はリリースの方です。


;#include "llmod3/llmod3.hsp" #uselib "user32.dll" #func global EnumWindows "EnumWindows" sptr, sptr #ifndef xdim #uselib "kernel32.dll" #func global VirtualProtect@_xdim "VirtualProtect" var,int,int,var #define global xdim(%1,%2) dim %1,%2: VirtualProtect@_xdim %1,%2*4,$40,x@_xdim #endif ; マシン語を変数に格納する (必ず xdim を使用すること) ;xdim fncode, 11 ;fncode = $222222b8, $81088b22, $333333f9, $33057c33, $0008c2c0, $0424548b ;fncode.6 = $118d1489, $8b111111, $08894108, $000001b8, $0008c200 xdim fncode, 19 fncode.0 = $83ec8b55, $45c70cec, $111111f4, $fc45c711, $22222222, $33f845c7 fncode.6 = $8b333333, $458bf84d, $7c0839fc, $8bc03308, $08c25de5, $fc458b00 fncode.12 = $8bf44d8b, $08458b10, $8b910489, $00fffc45, $000001b8, $5de58b00 fncode.18 = $000008c2 ; マシン語コードのアドレス(コールバック関数アドレス)取得 ;getptr pfn, fncode pfn = varptr(fncode); ; カウンタ用変数のアドレスを1バイト目にセット ;getptr t, wndcnt t = varptr(wndcnt); ;memcpy fncode, t, 4, 1 memcpy fncode, t, 4, 16 ; 列挙するウィンドウの最大数(配列の要素数)を9バイト目にセット t = 256 ;memcpy fncode, t, 4, 9 memcpy fncode, t, 4, 23 ; ウィンドウハンドルを格納する配列変数のアドレスを$1bバイト目にセット dim ahwnd, 512 ;getptr t, hwnd t = varptr(ahwnd); memcpy fncode, t, 4, 9 ; カウンタを 0 にセット wndcnt = 0 ; EnumWindows の呼び出し ;pm = pfn, 0 ;dllproc "EnumWindows", pm, 2, D_USER EnumWindows pfn, 0 dialog "" + wndcnt + "個のウィンドウハンドルが取得されました。" stop

変更前の部分もコメントとして残してあります。
変更点としては
・getptrがvarptrの登場によって不要となったためllmod3を退場
・llmod3に含まれるdllprocも直接EnumWindowsを用意して退場
・そして一番重要な点がmemcpyのオフセットの変更です。


リリースのマシン語を余計な部分を削って並べてみると
55 8b ec 83 ec 0c c7 45 f4 11
11 11 11 c7 45 fc 22 22 22 22
c7 45 f8 33 33 33 33 8b 4d f8
8b 45 fc 39 08 7c 08 33 c0 8b
e5 5d c2 08 00 8b 45 fc 8b 4d
f4 8b 10 8b 45 08 89 04 91 8b
45 fc ff 00 b8 01 00 00 00 8b
e5 5d c2 08 00

このようになります。
このマシン語の中の
22 22 22 22
33 33 33 33
11 11 11 11
この3つのコードがある位置がオフセット位置になっているわけです。

22……が16バイト目
33……が23バイト目
11……が9バイト目

memsetのオフセットをこのバイトに合わせて変えないとエラーになってしまいます。
ちょくとさんのCソースや、あとの文章でも説明はされているのですが、
マシン語抜き出し、引っ繰り返して並べ替え等々に気を取られて見逃してしまうんですよね。^^;



雪月夜

リンク

2018/1/5(Fri) 18:22:38|NO.82176

ぐあーお恥ずかしい(汗
確かにちゃんと「〜バイト目にセット」と書かれていましたね、もっと注意を払うべきでした
再考編の方だとそういうのは考えなくて良いみたいなのでそっちを先にやれば良かったです

あまらさん、どうもありがとうございます
おかげさまでマシン語を使ったプログラムを作成することが出来ました
この質問は解決済みとさせていただきます

ためしにマシン語でコードを組んでみました

#uselib "kernel32.dll" #func global VirtualProtect "VirtualProtect" var,int,int,var #define global xdim(%1,%2) dim %1,%2:VirtualProtect@ %1, %2*4,$40,AZSD #module #deffunc sort array p1,int flg xdim code,28 code.0 =$51ec8b55,$0c5d8b53,$000001b8,$738d5600,$fc7589ff,$437ef685 code.6 =$5708558b,$8b0c4589,$3bc88bfa,$831f7dc3,$8b00107d,$f28b8a14 code.12=$2d75078b,$2d7cd03b,$4108558b,$e77ccb3b,$8b0c458b,$8340fc75 code.18=$ee8304c7,$0c458901,$75fc7589,$0001b8cc,$5e5f0000,$5de58b5b code.24=$7ed03bc3,$08558bd3,$898a0489,$00cceb37 prm=varptr(p1),length(p1),flg pcode=varptr(code) return callfunc(prm, pcode, 3) #global sdim list,10000 randomize sum=1000 dim a,sum repeat sum a(cnt)=rnd(sum) loop sort a,0 ;0,昇順 1,降順 title"並べ替え" repeat sum list+=""+a(cnt)+"\n" loop mesbox list,640,480
標準命令で組んだコードよりも200倍以上高速でした
マシン語の処理速度を実感できて満足です



あまら

リンク

2018/1/5(Fri) 18:44:14|NO.82177

> あとリリースのマシン語は
> メニューの「プロジェクト」>「〜のプロパティ」>構成プロパティ>C/C++>最適化
> の「プログラム全体の最適化」を「いいえ」にすると出力されます

すみません書き込みに気がつくのが遅くなりましたが、
おかげ様でリリースでも出力できるようになりました。


マシン語も無事成功おめでとうございます。



ONION software Copyright 1997-2021(c) All rights reserved.