質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

MinGW

MinGW(ミン・ジー・ダブリュー)は GNUツールチェーンのWindows移植版です。 ランタイムライブラリと開発ツールで構成されています。

Q&A

解決済

2回答

448閲覧

Wine環境でのみWriteProcessMemoryがAccess denied.で失敗する

YouheiSakurai

総合スコア6142

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

MinGW

MinGW(ミン・ジー・ダブリュー)は GNUツールチェーンのWindows移植版です。 ランタイムライブラリと開発ツールで構成されています。

1グッド

1クリップ

投稿2018/12/26 05:50

編集2018/12/26 10:36

以下のコードから生成した実行ファイルの実行結果がWindowsとWineで異なり、行き詰まってしまったのでお知恵を借りたく質問します。なぜWine環境でだけWriteProcessMemoryが失敗するのでしょうか?何かしら回避策につながるヒントはありませんでしょうか?

問題のコード

Windows環境(10 バージョン1803)ではWriteProcessMemoryの返り値が非ゼロで成功しますが、Wine環境(wine-3.0.4)ではゼロが返りGetLastError()Access denied.が表示されます。

C

1#include <windows.h> 2#include <stdio.h> 3 4/* 5 * gcc poc.c -o poc.exe && poc.exe 6 */ 7 8 9void print_errmsg(DWORD error) { 10 char errmsg[512]; 11 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 12 NULL, 13 GetLastError(), 14 0, 15 errmsg, 16 sizeof(errmsg), 17 NULL); 18 printf("%hs", errmsg); 19} 20 21int main(int argc, char** argv) { 22 char* data = "123"; 23 DWORD access = PROCESS_VM_OPERATION|PROCESS_VM_WRITE; 24 25 HANDLE hProcess = OpenProcess(access, FALSE, GetCurrentProcessId()); 26 void* address = VirtualAllocEx(hProcess, 27 NULL, 28 sizeof(data), 29 MEM_COMMIT, 30 PAGE_READWRITE); 31 if (!WriteProcessMemory(hProcess, 32 address, 33 (void*)data, 34 sizeof(data), 35 NULL)) { 36 print_errmsg(GetLastError()); 37 return 1; 38 } else { 39 printf("OK!\n"); 40 } 41 42 return 0; 43}

コンパイラ情報

> gcc --version gcc (i686-posix-dwarf-rev0, Built by MinGW-W64 project) 8.1.0 Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Wine情報

$ printenv | grep WINE WINEDLLOVERRIDES=mscoree,mshtml= WINEDEBUG=fixme-all WINEARCH=win32 WINEPREFIX=/home/wineuser/.wine

試したこと #1

WineのWriteProcessMemoryこのブログの記述に反して、そのままNtWriteVirtualMemoryの呼び出しをしてそうなので、念のために以下の様なVirtualProtectを差し込んでみましたが結果は変わりませんでした。

C

1// 当方Cプログラミングは見よう見まねなのでaddressのアンパサンドあり・なしのどちらが正しいのかすら判別できないでいます。(多分前者が正解?) 2VirtualProtect(address, sizeof(data), PAGE_EXECUTE_READWRITE, &access); 3VirtualProtect(&address, sizeof(data), PAGE_EXECUTE_READWRITE, &access);

試したこと #2

WINEDLLOVERRIDESWINEDEBUGを空にしてWINEPREFIXに新しい場所を指定しても結果は変わりませんでした。

$ WINEPREFIX=/tmp/wine WINEDLLOVERRIDES= WINEDEBUG= wine poc.exe

試したこと #3

このスレッドで言及されているinjectdll.exeを試しても、Wine環境ではWriteProcessMemoryのところでcan't write to memory in that pidとなる。

試したこと #4

hProcessが毎回同じ値(WriteProcessMemory(00000020,...00000020)になるのが気になる。。。

wineuser@d2efe6cf1283:~$ WINEDEBUG=+all wine /opt/poc.exe 2>&1 | grep WriteProcess 30197.178:008a:008b:trace:imports:import_dll --- WriteProcessMemory KERNEL32.dll.1310 = 0x7b42854c 30197.332:008a:008b:Call KERNEL32.WriteProcessMemory(00000020,00230000,00404048,00000004,00000000) ret=004016de 30197.332:008a:008b:Ret KERNEL32.WriteProcessMemory() retval=00000000 ret=004016de wineuser@d2efe6cf1283:~$ WINEDEBUG=+all wine /opt/poc.exe 2>&1 | grep WriteProcess 30199.196:008c:008d:trace:imports:import_dll --- WriteProcessMemory KERNEL32.dll.1310 = 0x7b42854c 30199.359:008c:008d:Call KERNEL32.WriteProcessMemory(00000020,00230000,00404048,00000004,00000000) ret=004016de 30199.359:008c:008d:Ret KERNEL32.WriteProcessMemory() retval=00000000 ret=004016de wineuser@d2efe6cf1283:~$ WINEDEBUG=+all wine /opt/poc.exe 2>&1 | grep WriteProcess 30200.351:008e:008f:trace:imports:import_dll --- WriteProcessMemory KERNEL32.dll.1310 = 0x7b42854c 30200.521:008e:008f:Call KERNEL32.WriteProcessMemory(00000020,00230000,00404048,00000004,00000000) ret=004016de 30200.522:008e:008f:Ret KERNEL32.WriteProcessMemory() retval=00000000 ret=004016de wineuser@d2efe6cf1283:~$ WINEDEBUG=+all wine /opt/poc.exe 2>&1 | grep WriteProcess 30201.972:0090:0091:trace:imports:import_dll --- WriteProcessMemory KERNEL32.dll.1310 = 0x7b42854c 30202.132:0090:0091:Call KERNEL32.WriteProcessMemory(00000020,00230000,00404048,00000004,00000000) ret=004016de 30202.132:0090:0091:Ret KERNEL32.WriteProcessMemory() retval=00000000 ret=004016de

試したこと #5

VS2017/Ubuntu 16.04/wine-1.6.2で試してみましたが結果はAccess denied.となりました。

> cl /EHsc poc.c Microsoft(R) C/C++ Optimizing Compiler Version 19.13.26128 for x86 Copyright (C) Microsoft Corporation. All rights reserved. poc.c Microsoft (R) Incremental Linker Version 14.13.26128.0 Copyright (C) Microsoft Corporation. All rights reserved. /out:poc.exe poc.obj

実行環境の情報

試したこと #6

VS2017 (スタティックリンク)/Ubuntu 16.04/wine-1.6.2

> cl /MT poc.c Microsoft(R) C/C++ Optimizing Compiler Version 19.13.26128 for x86 Copyright (C) Microsoft Corporation. All rights reserved. poc.c Microsoft (R) Incremental Linker Version 14.13.26128.0 Copyright (C) Microsoft Corporation. All rights reserved. /out:poc.exe poc.obj root@6c9ee3b182f1:/# ls -l /tmp/poc.exe -rwxr-xr-x 1 root root 97792 Dec 26 10:35 /tmp/poc.exe root@6c9ee3b182f1:/# wine /tmp/poc.exe Access denied.
atata0319👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自己解決

原因はDocker上でWineを動かしていたことでした。(お騒がせしました)

解決策は--privilegedもしくは--cap-add SYS_PTRACEをDockerのオプションとして付与することでした。(Dockerの闇に足を取られていたようです)

SYS_PTRACEに関する情報

CAP_SYS_PTRACE

  • ptrace(2) を使って任意のプロセスをトレースする。
  • get_robust_list(2) を任意のプロセスに対して行う。
  • process_vm_readv(2) と process_vm_writev(2) を使って任意のプロセスのメモリーとの間でデータの送受信を行う。
  • kcmp(2) を使ってプロセス内部を調査する。

dodox86さん、お付き合いいただきありがとうございました。yoorwmさん、的確なヒントをありがとうございました。あのまま一人で悩んでいたら、あと最低でも40~50時間が闇に吸い込まれていた気がします。感謝です。

投稿2018/12/27 01:58

YouheiSakurai

総合スコア6142

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2018/12/27 02:42

おめでとうございます。動いた環境にただ合わせるのではなく、的確な解決策が見つかってよかったです。
guest

0

直接の回答ではなく、参考程度にとらえていただきたいのですが、VirtualBoxのUbuntu16.04(64ビット)で apt-get でインストールした wine-1.6.2 で実行したところ、エラー無く"OK!"と出力されて終了しました。
ただし、ご提示のコードをVisual Studio 2017 で32ビットのコンソールアプリケーションとしてビルドしたものです。

イメージ説明

今回の問題には直接関係無いはずですが、char *datasizeof(data)char*のポインタ型のサイズとなってしまうので、"123"のリテラル文字列のサイズとは意味が異なってしまい、VirtualAllocEx等に渡す引数の値としては不適切となってしまいます。たまたま末端の'\0'を入れて4バイトで32ビットで一致して、問題は生じませんが。。。

私の方では以下のように修正して試しています。これもご参考まで。。。

C

1... 2 //誤:char* data = "123"; 3 //const char* data = "123"; 4 const char data[] = "123"; 5 DWORD access = PROCESS_VM_OPERATION | PROCESS_VM_WRITE; 6...

投稿2018/12/26 09:11

dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YouheiSakurai

2018/12/26 09:30

すごくすごくありがとうございます!!コンパイラとOSとWineのバージョンを合わせて試してみます!取り急ぎ御礼までに。
dodox86

2018/12/26 10:29

追加情報ですが、同じ環境で64ビット版としてビルドしたEXEでもOKでした。また、お伝えしていませんでしたが32ビット、64ビット版ともにランタイムライブラリはDLLではなく、staticリンクしています。(“/MT”オプション) 普通に考えるとMinGWだろうがVCだろうがWineが提供するAPI内に入ったら影響は同じな氣がするのですが、リンク後のEXEの構成で何か実行時の属性などが変わっていたりするのかもしれません。(<単なる思いつきです)
YouheiSakurai

2018/12/26 10:31

質問に詳細を追記しましたが、手元ではご報告いただいた結果とは異なりました。。。相違点はexeファイルのサイズが若干違うのとwineコマンドを介さないとexeを実行できなかった2点かなぁと考えてます。なんでだろうなぁと悶々としておりますが、感謝の気持ちに変わりはありません。ありがとうございました。
dodox86

2018/12/26 10:43

なんでしょうね。(気になってきた)操作を真似てrootで実行したり、コンパイル方法を同じにしたりしましたがOKでした。あと思いつくのは、linuxのカーネルバージョンの違いでしょうか。。。
YouheiSakurai

2018/12/26 10:52

もしです、もし宜しければビルド済みの実行ファイルをDropboxやGithub経由でご提供いただけないでしょうか?リンクの公開等々がはばかれるようでしたら、こちらから何らかの手段を用意しますのでおっしゃってください。
dodox86

2018/12/26 11:47

Visual Studio 2017のプロジェクトとビルド済みファイルまるごとをZIPファイルにしてGoogle Driveにアップしました。以下のURLからダウンロードしてください。 https://drive.google.com/file/d/1-Zx4BNeeqHbuyho8dFKYm1h3VGJTmSwO/view?usp=sharing (アップしたファイルは一定期間の内、削除しますのでご了承ください) なお、ファイルは先ほど試したときは*.cppにしていたのですが、*.cにして再度ビルドし、x86ともx64 とも実行OKなことを再度確認しました。 ファイルのやり取りについてはこちらのコメント欄では読まれるであろう他の方々へ迷惑になるかもしれないので、もし長くなるようであればツイッターの方で連絡くださっても結構です。
YouheiSakurai

2018/12/26 13:44

どうもありがとうございます。ファイルをダンロードし、こちらの環境でConApp1_20181226a/Release/ConApp1.exeを動かしてみたところ、「Access denied.」となりましたので、自身の環境構築に問題がある可能性があると気づけました。今まで私はDockerを使用していたのですが、原因はそこかもしれないので、明日改めてVMにUbuntuをインストールして動作を見てみようと思います。ありがとうございます。
dodox86

2018/12/26 13:49

なるほど、Dockerでしたか。確かに何か匂いますね。
yoorwm

2018/12/27 00:54

--privilegedを付けると動くとか?
YouheiSakurai

2018/12/27 00:59

今、ちょうど「VM立てる前にprivilegedオプションを付けて確認しとくかぁ」と思い立ってやってみると動きました!!!!詳しくはもうちょっと調べてから追記します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問