他人の空似

2015 年 9 月 28 日

Splatoonの距離別命中率計測

Filed under: 未分類 — 中の人 @ 1:10 AM

最近Splatoonにはまっていまして、命中率について実際に計測しました。
せっかくなので結果をまとめて公開しようかと思います。

※追記:命中率表に信頼区間追加しました

計測方法

測定対象はオーソドックスにシューター13種だけ、またブラスターは対象外とした。
測定する距離は各武器の最大射程である1.5/2.2/2.8/3.1/3.6/4.5(試し撃ち場の点線一個分を1換算)の6種類。
ジャンプによる命中率の低下については今回は対象外。

距離の決定方法は、試し撃ち場にて線が引いてある広場の一番奥の人形相手を対象とし
その距離が最大射程である武器にて、照準が変化せず、なおかつ撃った際のイカ人形へのヒット位置があまり下すぎない程度に目視にて調整。
目視なため距離精度は高くないけれど、その場で武器持ち替えが可能なので、それを駆使して出来るだけ同一の距離で計測するように配慮した。
ただし、もともとは別の計測目的だったことや、計測中にH3リールガンの追加があったこと、WiiUの電源落ちてしまう事故があったなどで同一距離ではない計測も含まれている。

実際の計測方法は、1000発以上撃ちこんでその間に外れた回数を数えるという方法。
トリガーを引いたままでは目視による計測が難しかったため、1発だけ弾を撃ち着弾したかどうかを確認し再度1発だけ撃つを繰り返す形で行った。

また計測結果を元に命中率、Killを取るのに必要な射撃数の平均、各武器間での勝率計算、勝率有利がつく武器の数のカウントなどを行った。
勝率計算は弾速を考慮せず、1フレームでも先に相手をKill出来れば勝利、同一フレーム内なら引き分け、それ以外なら相手の勝ちとした。
なので通常であれば発射後着弾前の弾により相打ちとなる場合でもどちらかの勝利として数えられていることになる。

当然のことだが、機械的な計測ではなく完全な人力での計測なため、ある程度計測ミスが含まれていると思われる。
そのあたりを理解したうえで結果を読んでもらいたい。

計測結果

まずは命中率の表




次に勝率の表





感想とか雑多に

※※※ここから先は読まなくて大丈夫です※※※

計測を始めた時点ではwikiの拡散値から具体的にどの程度の命中率になるのかを調べるぐらいのつもりだったのですが、実際に計測してみれば
拡散値的には4.5対6で1.5も勝ってるはずの.96対スプラで.96が命中率で負けてる距離があったり
0.5しか差がないデュアルと.96で凄い差がついたり
逆に1違うはずのデュアルとプライムがほぼ同じ命中率だったり
と、明らかに現状の拡散値だけでは説明できない事象が多数観測されました。
これは現状のwikiに載っている拡散値が間違っているか、それと拡散値以外に何か命中率を大きく左右する要素があるか、といった話になります。
このあたりの情報持ってる人だれかいませんかね?

最終的な結果だけ見れば、概ね体感通りかなという印象ではありました。
たとえばボールドマーカーはカタログスペックよりはだいぶKill性能は低めである点、シャープマーカーは短射程組の中では飛びぬけてKill性能が高い点、.96ガロンはスプラシューターと同じぐらいな点などです。
これを新発見に乏しい無駄な計測だったとするか、体感通りの結果が数値付きで示された良い計測だとするかは皆様の判断に任せます。

一部平均Killタイム通りに有利不利がついていない武器がありますが、これはちゃんと「n発撃つのにかかる時間内に敵に撃ち殺される確率」のような計算をしているからです。
平均Killタイムが悪くても最速Killタイムが早ければ気持ち有利がつきやすいなどなど。
高速高威力かつ低命中率のボールドマーカーなんかがわかりやすいですね。

L3リールガンとH3リールガンで命中率に特に差はないと感じていますが、実際の計測結果としてはL3だけわずかに外れるという形になっています。
ですが、実はL3リールガンの距離3.1計測が全体で一番最初に行った計測で、つまり自分の計測経験値が足らなかったためイカ人形復活直後の判定なし状態で撃ちこんでしまったとか、そういう計測ミスの可能性があります。
しかし、そういった理由をつけて計測結果を取捨選択することは統計的にはやってはいけないことなので、最終的にはそのままの数値で出すことにしました。
元気があればL3リールガンだけ3000回ぐらい追加計測して最初の計測がおかしいかどうか検証してみたいですね。

より詳しい計測順序の話をすると
各武器で射程最大から撃った場合の命中率だけ計測しようと考えて計測、その結果をtwitterに投げる
しかし最大射程のしかないため射程が違う武器同士ではどちらが命中率が高いとか撃ちあった場合どちらが強いとかいう計算が出来ない
なら距離を揃えた計測もやろう!ということで今回の計測が始まりました。
29,000発以上イカ人形に撃ちこんだ計算になります、大変だった。
ちなみに、最大射程での計測結果はそのまま今回の計測に使いまわしているため、その距離が最大である武器だけ他とは微妙に違う距離で計測していることになります。

2015 年 6 月 6 日

touhouSE ver1.20リリース

Filed under: 未分類 — 中の人 @ 4:19 AM

東方系dat展開ツールtouhouSE更新しました。
http://wordpress.click3.org/garakuta/touhouSE.zip

東方深秘録対応版です。
完璧主義が発動して、1方向hashからファイル名を逆算する作業に明け暮れたため、3週間ほど出すのが遅れました。
その甲斐あって98%のファイル名は判明しているので、その周りでは特に困ったりはしないと思います。

2015 年 5 月 22 日

THxxBGMに深秘録製品版を追加するアプリリリース

Filed under: 未分類 — 中の人 @ 12:40 AM

THxxBGMに深秘録製品版の曲再生機能を足すアプリを作りました(一応心綺楼も増える)。
http://wordpress.click3.org/garakuta/thxxbgmTh145Patch.zip

使い方は、中のwinmm.dllをTHxxBGM.exeと同じディレクトリに置くだけ。
うまいこと行けばpath設定に心綺楼と深秘録が増えて、該当ディレクトリを設定すれば聞けるようになるはず。

2015 年 4 月 18 日

インクリメントの前置後置速度比較(vc++/gcc/clang)

Filed under: 未分類 — 中の人 @ 6:00 PM

後置インクリメントと前置インクリメントは基本的に前置の方がよいそうですが、自分は後置の方が書きやすくて好きなので、どこまでなら後置でもいいのか検証する目的で速度を測ってみました。

検証に使用したコンパイラのバージョン:
VisualStudio C++ 19.00.22609 for x86
gcc (GCC) 4.8.1
clang version 3.6.0 (tags/RELEASE_360/final)

検証環境はWindows10 TechnicalPreview

検証内容

典型的なfor文を前置後置それぞれのインクリメントを使用する形で作成。
インクリメント対象をunsigned int/iterator/適当に重めのクラスの三種それぞれを対象。
また、最適化により返り値計算が消えることを考えforの真偽判定でインクリメントの返り値を使用するものも用意。
以上をそれぞれ100,000,000回実行をさらに10回繰り返しかかった時間の平均をとる。
また、比較用に拡張forにてループまわすだけのも計測。

具体的なソースコードとコンパイルオプションは以下を参照。
ソースコード
コンパイルに使ったバッチファイル

以下読み飛ばしても通じる、検証をこの内容にした理由やらなんやら:

インクリメント演算子と言えば基本的にループで使用することが多いはず。
まれに+=1の代わりに使うこともありますが、それで行いうる処理はループも全て含んでいるでしょう。
他にも演算子オーバーライドなどでクラス独自に定義して使うこともあるかもしれませんが
そこまで行くと後置不利の根拠である値コピーがどーたらという前提すら崩れかねないですし
そもそも滅多にあるものでもないので今回は除外しました。

また、普通にforをまわすだけだと最適化で消え去ってしまうし、ある程度最適化を妨げようとすると今度はforが誤差になるぐらい処理速度を持って行かれてしまいます。
なので、インラインアセンブラでNOPを突っ込むことで対応。
それでもintのインクリメントをデクリメントに置換されたりいろいろしていますが、それは通常利用でも起きうるものとして許容しています。

クラス作成もいろいろ大変で、単にintをラップしたようなのを書くと当然ながら全部インライン展開されてint直と同じレベルまで最適化されてしまいます。
ですが、今回は後置の不利を検証するためなので残す必要があり、いい具合に重い処理として乱数を生成させました。
とはいえ乱数処理は重すぎるので1/1000しか動かないコードが入っています。

ちなみに、最適化の抑止の大変度合はclang>gcc>vcでした。
vcはNOP入れた以外では全部素直なコードを吐いて順当に遅かったです。
gccはクラスのインクリメントにて使いもしないメンバー配列をstd::copyしたら順当に遅くなりましたが、clangはそれすら最適化で消し去りました。
つまりclangが一番最適化は賢い、と思ったら最終的な計測結果ではgccに負ける感じに、詳しくは結果欄をどうぞ。

結果

vc++ gcc clang
拡張for 57ms 53ms 48ms
int前置インクリメント 46ms 61ms 41ms
iterator前置インクリメント 47ms 47ms 45ms
クラス前置インクリメント 320ms 47ms 316ms
int前置インクリメント、返り値使用 44ms 47ms 46ms
iterator前置インクリメント、返り値使用 44ms 37ms 46ms
クラス前置インクリメント、返り値使用 317ms 51ms 313ms
int後置インクリメント 51ms 44ms 53ms
iterator後置インクリメント 51ms 50ms 46ms
クラス後置インクリメント 2206ms 388ms 446ms
int後置インクリメント、返り値使用 55ms 50ms 50ms
iterator後置インクリメント、返り値使用 97ms 50ms 54ms
クラス後置インクリメント、返り値使用 2253ms 458ms 431ms

まず独自クラスは前置と後置で明らかに結果が異なり、後置が圧倒的に遅いです。
最小のclangでも1.5倍、最大のgccだと実に約9倍。
もちろんこれはコピーコンストラクタの重さに依存しますが、ある程度以上のクラスであれば必要のない後置インクリメントは避けた方がよさそうです。
また、地味ですがvc++のみ返り値使用の後置iteratorが前置の約2倍かかっています。
vc++においてはまだ「iteratorは最適化すれば消え去る」は幻想のようですね。

返り値の使用有無による変化は例外を除いて後置のクラスでのみでした(例外:前述のvc++後置iterator)。
おそらくintやiteratorであれば最適化の結果前後が消え去り、通常のメモリ=>レジスタ移動の範囲で解決できてしまうからでしょう。

なぜかgccだけクラス使用時の速度がとても速いです。
が、試行錯誤している間はずっとclangの方が速かったので、偶然今のコードではインスタンスが全部レジスタに載ったとかだと思われます。
ただしvc++がクラス使うと遅いのは最初から最後まで一貫していたので、この三つの中で一番遅いことは確定してよさそう。

他は特に速度の変化は見られません、また拡張forとの速度差も見られません。
なので、後置インクリメントでもプリミティブ型かiteratorなど薄いラッパークラスであれば速度に影響が出ることはない、と言っていいと思います。
(例外:vc++で後置インクリメントの結果を使う)
それ以外で後置インクリメントを使うこと自体そうあることではないですし、別に後置インクリメントをつける癖がついていても害はないと言っていいでしょう、あーよかった。

終わりに

前回せっかくclangやgccの環境を整えたので、以前から気になっていたインクリメントの速度計測をやってみました、いかがだったでしょうか。
個人的には後置の方が書きやすくて好きなので、現代の最適化の力を使えば特に害はなさそうとわかって一安心でした。

次はまた何かの速度計測をやるかもしれませんし、何かアプリ作るまで放置かもしれません。
ではまた。

2015 年 4 月 17 日

windowsにおけるただフォワードするだけの関数の機械語比較(VC++/gcc/clang)

Filed under: 未分類 — 中の人 @ 12:30 AM

本の虫さんの記事にて
linux上のGCCではただ別の関数へフォワードするだけの関数をコンパイルしてもPICが有効だとjmp一文にならない事とその理由を説明した記事を翻訳したものが載った。
そこでふと疑問に思ったのだが、PICとか関係のないwindows上ではどうなっているのだろうか?
というわけで、GCCとclangとVisualStudio2015それぞれでコンパイルして結果をまとめてみた。
なお、最適化の結果消え去るならば問題ないはずとの考えから最適化OFF/ON両方で検証している。

検証に使用したコンパイラのバージョン:
VisualStudio C++ 19.00.22609 for x86
gcc (GCC) 4.8.1
clang version 3.6.0 (tags/RELEASE_360/final)

検証コード

まずは検証に使うソースコードを載せる。

main.cpp

#include <iostream>

void OtherFile();
void TailProc();

void NormalProc() {
  std::cout << "Normal\n";
}

void CheckOtherFile() {
  OtherFile();
}

void CheckTailProc() {
  TailProc();
}

void CheckNormalProc() {
  NormalProc();
}

void TailProc() {
  std::cout << "Tail\n";
}

int main() {
  CheckOtherFile();
  CheckTailProc();
  CheckNormalProc();
  return 0;
}

lib.cpp

#include <iostream>

void OtherFile() {
  std::cout << "OtherFile\n";
}

一応解説しておくと、CheckOtherFileは定義が別の.cpp、CheckTailProcは同じ.cppだが後方で宣言、CheckNormalProcは前方で宣言となっている。

コンパイルに使用した.bat

cl /EHsc /Ox /GL /Fevc_exe.exe main.cpp lib.cpp
cl /EHsc /Od /Fevc_exe_O0.exe main.cpp lib.cpp
g++ -O3 -flto -o gcc_exe.exe main.cpp lib.cpp
g++ -O0 -o gcc_exe_O0.exe main.cpp lib.cpp
clang++ -O3 -o clang_exe.exe main.cpp lib.cpp
clang++ -O0 -o clang_exe_O0.exe main.cpp lib.cpp

clangのみ手元ではリンク時最適化できなかったため通常の最適化のみ。

gcc

最適化OFFの場合

main

各チェック関数

mainでなぜかcallが四つあるが一つ目おそらくコンパイラがつけた特殊関数だと思われる。
問題のcheck部分は元の記事ほど悪くはないがjmp命令ひとつまで縮んでいない。

最適化ONの場合
main

各チェック関数は三つとも完全にインライン展開されている。

VisualStudio C++

最適化OFFの場合

main

各チェック関数

チェック関数は三つともほぼ同じだったため他二つは割愛。

最適化ONの場合
main

三つとも完全にインライン展開されている。

clang

最適化OFFの場合

main

各チェック関数

mainの一つ目のcallはgccと同じくコンパイラが付与したもの。
チェック関数は三つともほぼ同じだったため他二つは割愛。

最適化ONの場合
main

OtherFileだけインライン展開されていないが、それは前述のとおりリンク時最適化が入っていないためと思われる。
CheckOtherFile自体はインライン展開されている。

まとめ

windows上だとVC++/gcc/clangのどれであっても、フォワードするだけの関数をjmp一文に翻訳してくれたりはしない。
だが、最適化を有効にすればどのコンパイラでも、別の.cppでも同じ.cppでも、大体インライン展開されてほぼコスト0になるので気にする必要はほぼない。

終わりに

VC++ではjmp一文にならないのは知っていたが、記事を読んだ範囲ではgccがjmp一文に翻訳するとしかおもえなかったため、コンパイラ比較にいい題材だろうと試してみた結果
このようなどれも結果がほぼ一緒で大した価値のない比較記事が生まれることとなりました、なんてこったい。

一応clangが文字数情報を生成してくっつけてくれてるとか、VC++はmainはほぼ書いたまんまだけどその他は前後にちょっと追加があるとか、clangのフォワード関数部分はgccではなくVC++寄りだとか、見どころはないでもないが全部本題とは無関係である。

まぁ、可読性のために別関数にしたりするぐらいではそう滅多にオーバーヘッドは生まないことが分かっただけでも収穫だろうか。

なにか間違いなどありましたらコメントください。
ではまた。

2015 年 4 月 1 日

Windowsのセキュリティ機能Control Flow Guard解説

Filed under: 未分類 — 中の人 @ 4:44 AM

Windows8.1 updateから入ったセキュリティー機能であるControl Flow Guard(以降GuardCF)について調べたのでまとめておきます。

本記事を書く上で、以下のサイトを参考にさせていただきました。
http://www.ffri.jp/blog/2015/01/2015-01-05.htm

IMAGE_OPTIONAL_HEADER32など本稿にあまり関係のない部分については特に解説しないので、必要なら別途ググるなどしてください。

GuardCFとは何か

ざっくりと説明すると「呼び出す関数が実行時に決定されるコードから呼び出せるアドレスをホワイトリストで管理し、それ以外を実行しようとしたらクラッシュする機能」です。
たとえばC++の仮想関数、dllを動的リンクした際のGetProcAddressの返り値、関数ポインターを経由した呼び出し、などなどが対象。
主に、仮想関数テーブルを上書きすることで仮想関数実行時に任意のアドレスを実行させる、俗にいうvtable overwriteを防ぐための機能です。

パスの解析やらは一切やっておらず、バグか脆弱性がない限りここではAは呼ばれないと自明な場合でも、Aがホワイトリストに入っていればAの呼び出しを許可してしまいます。
おそらくこれは速度的な都合か、キャストを駆使されると確実な追跡が難しいというあたりかと。

また、仕組み上GuardCFは.exeだけではなくリンクする.dllでもすべて有効になっていなければ効果が激減します。
win8.1 update以降であればwindows提供の.dllの大半はGuardCFがかかった状態で提供されていますが、サードパーティー製の.dllなどを使う場合、GuardCFが有効かチェックしてから使うとよいでしょう。

実際に作成してみたい場合、2015/04/01現在preview版であるVisualStudio2015の14.0.22609.0 D14REL以降を使う必要があります。
C/C++のコンパイルオプションに「/d2guard4」、Linkerのオプションに「/guard:cf」を追加してコンパイルすればGuardCFが有効な.exe/.dllを作成できます。
詳しくはFFRI様の記事を参照のこと。

次は具体的にどのようにして処理されているのかを説明しましょう。

具体的にはどういう仕組みなのか

まずコンパイル時に動的呼び出しされうるアドレスの一覧を作成する必要があります。
正式に資料に載っていたわけではなく動作から推測した内容ですが、仮想関数/dllexportした関数/&演算子などでアドレス取得された関数、のどれかに合致した物をすべてホワイトリストとして扱うようです。

次に実行時に呼び出すアドレスが確定するコードの直前に「guard_check_icallというホワイトリストに含まれるかを調べる関数」を呼び出すようコードを追加します。

次はリンクして.exeを生成する際にGuardCFにまつわる情報を付加します。
中身は、guard_check_icallで呼び出すアドレス格納位置、GuardCFのホワイトリスト、GuardCFの動作にまつわるフラグ、の3種になります。
これの詳細ついては後述します。

そして実行時、まず通常通り.exeをロードしますが、その際にguard_check_icallは通常のリロケーション処理に基づき、単にRETNするだけの関数へ向けます。
その後、win8.1 update以降である場合はGuardCF用情報を元に、guard_check_icallが呼び出す先のアドレスをどこに保持しているかを突き止め、それをntdll.guard_check_icall_fptrに変更します。
これにより、旧来のOS側の専用処理をいれることなく従来のロード処理だとチェックがスキップされ、win8.1 update以降でのみGuardCFが有効になるわけです。

次に実際のチェックです。
以下のうちどれかに合致すると実行してもよいと判断するようです。

  • 実行しようとしているアドレスが事前に各種.exeや.dllから集めたホワイトリストの中に含まれている
  • GuardCFがかかっていない.dll/.exe上のアドレスを指している
  • .dllや.exeに属さない動的確保したメモリー上で、なおかつそのメモリーに実行可能属性がついている

そして、実行するべきではないと判断した場合は強制的にクラッシュして、被害を最小化する、という動作になります。

.exe/.dllに付与されるGuardCF情報詳細

IMAGE_OPTIONAL_HEADER32内のDataDirectoryのIMAGE_DIRECTORY_ENTRY_LOAD_CONFIG(=10)に格納されています。
これはIMAGE_LOAD_CONFIG_DIRECTORY32構造体がそのまま入っていて、VC++2015以降であればGuard*というメンバーがあるのでそれを使います。
※GuardFlagsは0x58にあるのに14.0.22609.0 D14REL時点ではIMAGE_DATA_DIRECTORY上はsizeが0x40と出力されます、が、IMAGE_DATA_DIRECTORY.sizeが間違っているだけで、IMAGE_LOAD_CONFIG_DIRECTORY32.Sizeは正しい値なのでそちらを参照のこと。

以下各パラメーターの説明。

  • GuardCFCheckFunctionPointer:前述したguard_check_icallで呼び出す先のアドレスが格納されている場所の仮想アドレス、offsetではないのでベースアドレスの変動を考慮する必要がある
  • GuardCFFunctionTable:ホワイトリストの仮想アドレス、4byteのアドレスがGuardCFFunctionCount個分並んでいる、こちらもoffsetではない点に注意
  • GuardCFFunctionCount:ホワイトリストの数
  • GuardFlags:WinNT.h内のIMAGE_GUARD_*のフラグ群をorしたもの、ちゃんと調べたわけではないがIMAGE_GUARD_CF_FUNCTION_TABLE_PRESENTを入れるとGuardCF有効とみなされる模様

Q&A

その他雑多にいろいろ書いておきます。

    • Q結局どうすればいいの
    • A何も考えずに.exe/.dllすべてでGuardCFを有効にすればいいとおもいます
    • Qバイナリしか提供されていない.dllにGuardCFかかってなかったんだけど
    • Aどうしようもありません、あきらめましょう
    • Q GuardCFをかけることのデメリットは?
    • Aだいぶ安全側に倒した実装になっているので一般的には処理速度の低下だけだと思われます、また一部の人にとっては外部ツールによる機能拡張が大変になるというデメリットもあります。
    • Q処理速度にどれぐらい影響するの?
    • A自分も知りたいので計測して記事書いてください、見に行きますので。
    • Q IMAGE_OPTIONAL_HEADER32内の~あたりからさっぱりわからん
    • A IMAGE_DOS_HEADER、IMAGE_NT_HEADERS32、IMAGE_DATA_DIRECTORYあたりでググって出てきたページ片っ端から読む方が自分が説明するよりわかりやすいとの判断により説明していません。

終わりに

どうでしたでしょうか?
実はこれエクスプロイトを書きつつ学ぶWindowsセキュリティー機能 ~番外編SEHOP~の続編にするつもりだったんですが、/DYNAMICBASE:NOを指定するとなぜかGuardCFが働くなってしまい、どうしてもexploitがASLR回避に比重が置かれるため断念したという経緯で書かれたものになります。
そのためただ情報を列挙しただけで、読みづらい感じに……。
まぁそれでも人によっては役に立つ資料となるでしょう。

どうか、一人でも多くこういったセキュリティー機能に興味を持ってくれることを祈ります。
そして自分で書かなくてもググれば見つかる世の中になったらいいな。

2015 年 3 月 30 日

.dll/.exe外部関数一覧調査アプリリリース

Filed under: 未分類 — 中の人 @ 1:48 AM

.dllや.exeでimportしている外部関数一覧を表示するアプリ作りました。
http://wordpress.click3.org/garakuta/dll_import_list.zip
詳細ページ

静的リンクでどんな.dllにリンクしていて、どんな関数を実行しているかを調べるアプリ。
自分なんかが作らなくてもその辺にごろごろしてそうだが、単に手元のHDD上にしか存在していなかったので、バックアップを兼ねて公開してみただけ。

2015 年 3 月 18 日

Jane Style広告ブロックアプリリリース

Filed under: 未分類 — 中の人 @ 2:54 AM

Jane Styleの広告をブロックするアプリ作りました。
http://wordpress.click3.org/garakuta/jane_style_ad_block.zip
詳細ページ

ほとんど自分用、もしくはバイナリエディタとか使えない初心者向け。
巷では1byteのバイナリパッチで広告ブロックする手法が出回っていますが、毎回解析したりするのがだるそうだったので
機械語にパッチあてずに何とかして、exeが更新されてもよっぽどじゃないと動くようなのを目指して作りました。

2015 年 3 月 16 日

自作物一覧公開しました

Filed under: 未分類 — 中の人 @ 1:39 AM

zip作って放置するだけだった自作物を一覧できるようにしました。
自作物一覧
一応サイト右上のリンクからも飛べます。

2015/03/16現在全部で63個あります。
また、せっかくなので過去バージョンのダウンロード機能つけたり、一言説明つけたり、ダウンロードせずにReadmeやソースコード閲覧できる機能つけたりもしてあります。
atomのフィードも自作物一覧全体と個々の自作物ごとでそれぞれ備えているのでフィードリーダーガチ勢でも安心。

2015 年 2 月 7 日

.pngから.curを作成するアプリリリース

Filed under: 未分類 — 中の人 @ 5:09 PM

.pngから.cur(マウスカーソルとかのアレ)を作成する小物アプリ作りました。
http://wordpress.click3.org/garakuta/png2cur.zip

元々は友人の手伝いで作った小物なのであんまり実用性はない。
が、それでも一応作ったものなので、適当にreadmeとかこさえて公開しとく事にしました。
(いないと思うけど).curを大量作成する必要に駆られている人とかいたらどうぞ。

Older Posts »

Powered by WordPress