究極のエロ画像保存法

もくじ

はじめに
エロファイル隠蔽の根源的問題
それでもリソース化する。
そうだ! レジストリに保存すればいいんだ。
必殺、メールにしちゃおう攻撃。
ほかのファイルに寄生したらいいかもね。
偽装してみましょうか。
サブストリームに隠そうぜ![NTFS限定]

はじめに

PC上でエロ画像の隠し方は古来より様々な場所で議論されてきました。 zipで固める、システムフォルダに投げる、ダミーフォルダを作る、といった初歩的な方法から、 1度見たら削除、仮想ドライブを作る、ファイルを偽装する、といった上級者まで、 試行錯誤が繰り返されてきました。

現在の所、ファイル隠蔽ソフトMirage Colloid(愛称ミラコロ)の利用で合意が得られています。 大変優れたソフトです。パスワード制なので少々のことでばれることはありません。 元データを改変しないので時間もかかりません。

VectorのMirage Colloidダウンロードページ

TrueCryptもよく利用されています。TrueCryptは、仮想ドライブを扱います。

エロファイル隠蔽の根源的問題

私たちが手順に従って、エロファイルを隠し、また取り出すことが可能ならば、 他の人でもエロファイルにアクセスすることができるわけです。

メソッド必要スキルリスク解説
フォルダ名を「数学課題」にする★☆☆☆☆★★★★★すぐにばれる。
フォルダ階層く深くする★☆☆☆☆★★★★★検索で一発。
拡張子を偽装する★★☆☆☆★★★★☆開くまで手間がかかる。極窓で一発。
zipで固める★★★☆☆★★★★☆露骨に怪しい。パスかけてたらなおさらあやしい
ヘッダ偽装★★★★☆★★★☆☆開けない→ゴミ箱行きになるかも。
削除して復元ソフトで閲覧★★★☆☆★★★★★下手をすると見れなくなる。デフラグされたら涙目。
base64エンコードしてメーラーで閲覧★★★★☆★★★★☆ファイルサイズはでかくなるし、手間もかかる。エロ動画には向かない。
CDやDVDに焼いたり外付けメディアの使用★★☆☆☆★★☆☆☆比較的安全だが、物理的にブツを隠す問題が発生する。
見ないように説得する★★★★★★★★★★人の心を制してしまえば完璧かも。
グロ画像を1つ上のフォルダに撒く★☆☆☆☆★★★★★グロ画像を先に置いておけば、それ以上フォルダを見られることはないかも。
アカウントを分ける。パスワード付き。★☆☆☆☆★☆☆☆☆後ろからのぞかれない限り大丈夫でしょう。隠し設定にしておくとさらに安心。

家族のpcスキルが低くても、いずれは見つかる可能性があります。 フォルダを深くしても、フォルダ名を「数学課題」にしてもwinsowsフォルダにいれても、 検索で一発です。 拡張子偽装をしても、ファイルのヘッダを見ればある程度予測はできます。 zipに固めても、cabで固めても、パス付けても、露骨に怪しいだけです。 ファイルのヘッダを偽装すると、壊れたフィルと思われ削除されるだけです。

それでもリソース化する。

ミラコロを使えば問題ないのですが、私はリソース化を提示しておきます。 リソース化は面倒ですが、大量のファイルを1つのファイルにまとめることができます。 また、データをDLLやEXEに埋め込むので、相手がハッカーとかプログラマでない限り 見つかる心配はありません。 リソースはXNResourceEditorなどを使えば簡単に追加、差し替え変更ができます。 Microsoft Visual C++の場合を前提に書いています。

手順
1,エロファイルを用意する
2,リソーススクリプトを書く
3,リソーススクリプトをもとにエロファイルをリソースファイルにする
4,リソースファイルをDLLにする
5,このDLLにアクセスするプログラムをつくる

リソースファイルを作りDLLにしてしまう

まずリソースファイルを作ります。 リソーススクリプトを書きます。

1 JPEG "eri1.jpg"
2 JPEG "ai2912.jpg"
3 JPEG "reina123.jpg"
4 JPEG "test.jpg"

こんな感じです。単純ですよね。 最初の数値がリソースIDと呼ばれるものです。他と重ならない数値であればなんでもいいです。
2つ目のJPEGはリソースタイプといいます。べつにJPEGでなくても自分が分かればjpgでもJgでもaaaでもかまいません。
3つ目が実際のファイルです。フルパスでも相対パスでもかまわんでしょう。
これを延々書き連ねるだけです。 今回はeroimg.rcで保存したものとしてお話をすすめます。

リソースコンパイラでリソースファイル(拡張子res)にします。 もしかしたら警告が出るかもしれません。

rc  eroimg.rc

なにも表示されませんが、eroimg.resが出来ると思います。 つぎにこれをDLLにします。VCのリンカなら次のようにします。

link /DLL /NOENTRY eroimg.res

警告が出ますが、これでDLLが出来るはずです。 どうしても気になる人は/machineオプションを入れてみてください。

読み取りプログラムの作成

つぎにこのDLLからデータを読み取るプログラムをつくります。 GetEroImg.cで保存を前提。

/*
GetEroImg.c 
リソースを含むDLLからjpgファイルを取り出す。
*/

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
DLLからデータを取り出す

DLLname = DLLファイル名
type    = リソースタイプ
id      = リソースID
size    = データのサイズが返る(ポインタ)関数が失敗したら変化無し。

成功したらデータが返る。使い終わったらfreeすること。
失敗したらNULLが返る。
*/
char *ReadRes(const char *DLLname, const char *type, DWORD id, DWORD *size)
{
    HMODULE hModule;
    HRSRC hrsrc;
    DWORD ressize;
    HANDLE hres;
    char *res;
    char *data;
    
    //DLLを開きまくる
    hModule = LoadLibrary(DLLname);
    if (hModule == NULL) {
        puts("dll読み込めないよ");
        return NULL;
    }
    //指定idのリソースを探す
    hrsrc = FindResource(hModule, MAKEINTRESOURCE(id), type);
    if (hrsrc == NULL) {
        puts("お探しのリソース見つからず");
        FreeLibrary(hModule);
        return NULL;
    }
    //サイズ取得
    ressize = SizeofResource(hModule, hrsrc);
    if (ressize == 0) {
        puts("リソースが0バイトって");
        FreeLibrary(hModule);
        return NULL;
    }
    
    hres = LoadResource(hModule, hrsrc);
    if (hres == NULL) {
        puts("LoadResource失敗");
        FreeLibrary(hModule);
        return NULL;
    }
    
    //データのポインタを取得
    res = (char *)LockResource(hres);
    if (res == NULL) {
        puts("LockResource失敗");
        FreeLibrary(hModule);
        return NULL;
    }
    //コピー
     data = malloc(ressize);
    if (data == NULL) {
        puts("メモリ足りない");
        FreeLibrary(hModule);
        return NULL;
    }
    memcpy(data,res,ressize);
    FreeLibrary(hModule);
    *size = ressize;
    return data;
}

int main(int argc, char *argv[])
{
    char *jpgdada;
    DWORD jpgsize;
    FILE *fp;
    DWORD id;
    char dllnam[MAX_PATH], outfile[MAX_PATH];
    
    //引数不足の場合使い方を示す
    if (argc < 3) {
        puts("GetEroImg DLLの名前 取り出したいリソースID [作るファイルの名前]");
        return 19880817;
    }
    
    //
    strcpy(dllnam, argv[1]);
    id = atoi(argv[2]);
    
    if (argc > 3) {
        strcpy(outfile, argv[3]);
    } else {
        //指定が無ければ勝手に作る
        SYSTEMTIME st;
        GetLocalTime(&st);
        sprintf(outfile, "%04d%02d%02d_%02d%02d%02d.jpg", 
            st.wYear, st.wMonth, st.wDay,st.wHour, st.wMinute, st.wSecond);
    }
    
    //データを取り出す
    jpgdada = ReadRes(dllnam, "JPEG", id, &jpgsize);
    if (jpgdada == NULL) {
        puts("リソースを読み込めません。DLLファイル名とIDを確認してね。");
        return 19881006;
    }
    
    printf("%sから%s(%dバイト)を作ります...\n", dllnam, outfile, jpgsize);

    //ファイルに書き出す
    fp = fopen(outfile, "wb");
    if (fp == NULL) {
        puts("ファイル作れん");
        return 19831101;
    }
    if (fwrite(jpgdada, 1, jpgsize, fp) != jpgsize) {
        puts("失敗しました。");
        fclose(fp);
        remove(outfile);
    } else {
        fclose(fp);
        puts("成功。");
    }
    free(jpgdada);//すぐ終了するからfreeする必要なし
    return 0;
}

ReadRes関数でリソースからデータを取り出します。 当然ですがDLLファイル名と、リソースタイプとIDが合えば、正しく取り出せます。 取り出したデータはファイルとして書き出します。 ファイル名の指定が無ければ勝手に作ります。

GetEroImg eroimg.dll 1

とすれば、eri1.jpgが復元されます。(ファイル名は本日の日時になりますが)

発展

読み込んだデータをそのまま表示するプログラムを作れば、 ファイルにしなくてすむので安全でしょう。 さらに多くのリソースタイプに対応させれば面白いと思います。 このプログラムでもリソースタイプがJPEGであればどんなファイルでも取り出せるけどね。

Digital Mars C/C++の場合

ここではDMCの時の方法を。

用意するのはDMC一式とDMCのリソースコンパイラです。

リソースを作るにはrcc.exeを使います。

rcc eroimg.rc

これでリソースファイルが出来ます。 でDLLにするんだけど、VCのリンカだと形式がちがうためエラー (fatal error LNK1136: invalid or corrupt file) が出てリンクできません。 omf形式対応のリンカならできるかも。

dmcのlink.exeを使いたいんだけど、リソースだけにするオプションが分からん。 しかたないから次のようなダミーファイルを作ってコンパイルします。

/* eroimg.c */
#include <windows.h>

BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
    return  TRUE;
}

これをリソースファイルとともにDLLにします。 DMCでDLLを作るときは必要なライブラリを全部教えないといけません。

dmc eroimg.c eroimg.res kernel32.lib -WD

つぎのようにリソーススクリプトのまま渡す手もあります。 こっちだと自動的にrccに渡してくれるので便利かも。

dmc eroimg.c eroimg.rc kernel32.lib -WD

あとはリソース読み込みプログラムをつくるだけ。

GUI版

とりあえずGUI版作ってみた。 ソース貼ると長いから zipで固めておく

そうだ! レジストリに保存すればいいんだ。

レジストリに保存する。 これなら、難しい操作なんか必要ありません。 バイナリエディタとレジストリエディタがあれば、手打ちで レジストリに保存することが出来るからです。

でも数バイトのデータならまだしも、普通の画像ファイルとかになってくると、気が遠くなります。 だから私は、ファイルをレジストリに保存するプログラムを組んでみました。 取り出すことも出来ます。 ただし、単なるレジストリへの入出力テストプログラムに成り下がっています。

setregとgetreg関数が実際にレジストリへアクセスする関数です。 あとはオマケです。

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef USE_GC
#include "gc.h"
#pragma comment(lib, "gc.lib")
#define malloc GC_MALLOC
#define free
#endif

// レジストリにデータを書き込む。
// HKEY_CURRENT_USER\Software\sakiyaのnameにbufをsizeだけ保存する。
// 成功=0以外 失敗=0
int setreg(char *name, char *buf, long size)
{
    HKEY hkey;
    long ret;
    
    if (name == NULL || buf == NULL || size == 0) return 0;
    
    ret = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\sakiya", 
        0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL);
    if (ret != ERROR_SUCCESS) return 0;
    
    ret = RegSetValueEx(hkey, name, 0, REG_BINARY, buf, size);
    
    RegCloseKey(hkey);
    if (ret != ERROR_SUCCESS) return 0;
    return 1;
}

//レジストリからデータを取り出して返す。
// HKEY_CURRENT_USER\Software\sakiyaのnameからデータを取り出して返す。
//size(ポインタ)にデータサイズを返す。
//失敗したらNULLを返す。
char *getreg(char *name, long *size)
{
    HKEY hkey;
    long ret;
    char *p = NULL;
    DWORD type;
    
    ret = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\sakiya", 
        0, KEY_READ, &hkey);
    if (ret != ERROR_SUCCESS) return NULL;
    
    type = REG_BINARY;
    
    //データのサイズを得る。
    ret = RegQueryValueEx(hkey, name, 0, &type, NULL , size);
    if (ret != ERROR_SUCCESS) goto ERR;

    p = malloc(*size);
    ret = RegQueryValueEx(hkey, name, 0, &type, p , size);
    if (ret != ERROR_SUCCESS) {
        free(p);
        p = NULL;
        goto ERR;
    }

ERR:
    RegCloseKey(hkey);
    return p;
}

// ファイルfileを開いて中身を返す。 sizeにファイルサイズを戻す。 NULLなら失敗。
char *readfile(const char *file, long *size)
{
    FILE *fp;
    char *buf;
    
    *size = 0;
    fp = fopen(file, "rb");
    if (fp == NULL) return 0;
    if (fseek(fp, 0, SEEK_END) == -1) goto ERR;
    if ((*size = ftell(fp)) == -1)  goto ERR;
    rewind(fp);
    
    if ((buf = malloc(*size)) == NULL) goto ERR;
    fread(buf, 1, *size, fp);
    fclose(fp);
    return buf;
    
ERR:
    fclose(fp);
    return NULL;
}


//fileにbuf(sizバイト)を書き出す。
int writefile(char *file, char *buf, long siz)
{
    FILE *fp;
    char fnam[260];
    
    sprintf(fnam, "(書き込みテスト)%s", file);
    
    fp = fopen(fnam, "wb");
    if (fp == NULL) return 0;
    fwrite(buf, 1, siz, fp);
    fclose(fp);
    return 1;
}

// 最後の\以下を返す。
void getfilename(char *path, char *name)
{
    char *p;
    
    p = strrchr(path, '\\');
    if (p == NULL) {
        strcpy(name, path);
    } else {
        strcpy(name, p+1);
    }
    return;
}

int main(int argc, char *argv[])
{
    char *p;
    char name[300];
    int s;
    
    if (argc < 2) {
        //使い方を示して終わる
        puts("引数に入れたファイルを\n"
        "レジストリHKEY_CURRENT_USER\\Software\\sakiya\n"
        "に保存します。");
        return 0;
    }
    
    while (--argc) {
        //データ書き込みテスト
        p = readfile(argv[argc], &s);
        //if (p == NULL) continue;
        getfilename(argv[argc], name);//ファイル名+拡張子を得る。
        printf("%s (%dバイト)をレジストリに保存しています。", name, s);
        if (setreg(name, p, s)) {
            puts("成功しました。");
        } else {
            puts("失敗しました。");
        }
        free(p);
        
        //データ読み込みテスト
        p = getreg(name, &s);
        if (p != NULL) {
            printf("%s (%dバイト) 読み込み成功 ", name, s);
            //さらに読み込んだデータを書き出してみるテスト。
            if (writefile(name, p, s)) {
                puts("書き込み成功。");
            } else {
                puts("書き込み失敗。");
            }
        } else {
            puts("読み込み失敗。");
        }
        
        free(p);
    }
    return 0;
}

上のプログラムをコンパイルしたもの。(f2r.zip)

必殺、メールにしちゃおう攻撃。

メールにしてしまえばメーラーで簡単に閲覧することができます。 しかも怪しまれることもないと思います。メールさえ見られなければね。

日本語メールはJIS形式(iso-2022-jp)に、 画像などのファイルを添付するときは、BASE64という形式に エンコードするのが一般的です。 BASE64エンコードはファイルサイズが大きくなるため、 大きなファイルを扱うには向いていません。 エロ動画を扱うにはこの方法は不向きです。

エロ画像をドロップするだけでエロ画像添付メールを生成するソフト。 cb64.zip

ほかのファイルに寄生したらいいかもね。

この方法は他の方法よりもリスクが小さく、高速で、 CRCで改ざんもチェックできるので、最良だと確信している。

たとえばexeファイルに寄生した場合を考えよう。 exeファイルはエントリポイント(main)から機械語通りに読みこまれるため、 寄生先にも影響はでないしエロファイルまでジャンプするようなバグでもない限り見つからない。

レジストリやリソースは見つかりにくいと言ってもMSのフォーマットなので、 すこしでもWin32APIに造詣のあるものは解析してしまうかもしれない。 TARなどネットに公開されているアーカイブも同様だ。

だから私は以下のようなオリジナルのエロファイル寄生フォーマットを考案した。

-----------------
exeファイルなど寄生先
-----------------
エロファイル1
-----------------
エロファイル2
-----------------
...
-----------------
フッタ
-----------------

この方法は一般のアーカイブと違い、寄生という概念がある。

次にフッタ構造。 単純にCOPYコマンドで結合することもかのうだが、 これでは取り出すことができないし、 ファイルサイズを記憶しておきバイナリエディタなどで取り出しても、 それが正常なエロファイルと断言できない。

フッタは簡単に扱えるように以下のようにした。(ulong=unsigned long)

[フッタ識別子1]
"鈴木えみ"(8byte)

[ファイル情報]
ファイル名(文字列、終端nul)
ファイルサイズ(ulong値)
CRC値(ulong値)
付加情報(ulong値)

...


[フッタ識別子2]
"鈴木友菜"(8byte)

[エロファイルの先頭位置]
ulong値(4byte)

[フッタ先頭位置]
ulong値(4byte)

[エロファイルの数]
ulong値(4byte)

特徴は2つのフッタ識別子がSJISの2バイト文字ということ。 これで高セキュリティが維持できるだろう。 さらにCRC値を保持することで信頼性が増している。

付加情報は現在のバージョンでは使用していない。 ファイルを暗号化した際のキーなどを考えている。

実装とソース

使い方。全てDOS窓で行う。

寄生。
eroc -c 寄生先ファイル エロファイル1 エロファイル2 ...

抽出
eroc -d 寄生先ファイル
番号を聞いてくるので、抜きたい番号を入力しEnterキー。

削除
eroc -e 寄生先ファイル
結合したエロファイルが全て削除される。

偽装してみましょうか。

すでにロリコンバータ(乙)という 面白いソフトが存在するので、これをお手本にすこしだけ形式の違うものを作ってみましょう。

ロリコンバータ(乙)はビットの0, 1をそれぞれ'ロ', 'リ'に変換しているので変換後8倍になります。 ここでは2ビットずつの変換で4倍に収めます。

4文字ですぐに思いつくのはセクロスですので、0b00='セ', 0b01='ク', 0b10='ロ', 0b11='ス'と対応させます。

次に1バイトデータの読込ですが、下位ビットから読み取ります。 よって0b01001110(0x4E='N')ならロスセクとなります。

//ファイル偽装
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//変換表
static const unsigned char ctbl[] = "セクロス\r\n";

//エンコード
int _fastcall encode(char *infile, char *outfile)
{
    int c, d, i, ret;
    FILE *in, *out;
    
    fprintf(stderr, "偽装 : %s -> %s\n", infile, outfile);
    
    d = ret = 0;
    in  = fopen(infile,  "rb");
    out = fopen(outfile, "wb");
    if (in == NULL || out == NULL) {
        fprintf(stderr, "ファイルを開くことができません。\n");
        goto ERR;
    }

    while ((c = fgetc(in)) != EOF) {
        for (i=0; i < 8; i+=2) {
            fputc(ctbl[(c>>i) & 0x3], out);
        }
        d += 4;
        if (d >= 80) {
            fwrite("\r\n", 1, 2, out);//改行
            d = 0;
        }
    }
    ret = 1;
    fprintf(stderr, "偽装完了 %dKB->%dKB\n", ftell(in)/1024, ftell(out)/1024);
ERR:
    if (in) fclose(in);
    if (out) fclose(out);
    return ret;
}

//偽装ファイルか?
int checkscrsfile(FILE *fp, int i)
{
    int p, n, c;

    p = ftell(fp);
    for (n=0; n<i;i++) {
        c = fgetc(fp);
        if (c == EOF) break;
        if (strchr(ctbl, c) == NULL) {
            fseek(fp, p, SEEK_SET);
            return 0;
        }
    }
    fseek(fp, p, SEEK_SET);
    return 1;
}

//改行を無視して4バイト読み込む
int _fastcall get4byte(FILE *fp, char *r)
{
    int c, cnt = 0;//読み込み数
    
    while ( (c = fgetc(fp)) != EOF) {
        if (c == '\r' || c == '\n') continue;
        r[cnt] = c;
        cnt++;
        if (cnt == 4) break;
    }
    return cnt;
}


//エンコードされた4バイトをもとの1文字に戻す
unsigned char _fastcall conv(unsigned char *r)
{
    int i, j, n;
    unsigned char ret = 0;
    
    for (i=0; i<4; i++) {
        for (j=0; j<4;j++) {
            if (ctbl[j] == r[i]) break;
        }
        ret |= ((j&0x3) << (i*2));
    }
    return ret;
}

//デコード
int _fastcall decode(char *infile, char *outfile)
{
    unsigned char r[4];
    FILE *in, *out;
    int ret;
    
    fprintf(stderr, "復元 : %s -> %s\n", infile, outfile);
    
    ret = 0;
    in  = fopen(infile,  "rb");
    out = fopen(outfile, "wb");
    if (in == NULL || out == NULL) {
        fprintf(stderr, "ファイルを開くことができません。\n");
        goto ERR;
    }
    if (checkscrsfile(in, 200) == 0) {
        fprintf(stderr, "偽装ファイルではないと判断されました。\n");
        goto ERR;
    }
    
    while (get4byte(in, r) == 4) {
        fputc(conv(r), out);
    }
    ret = 1;
    fprintf(stderr, "復元完了 %dKB->%dKB\n", ftell(in)/1024, ftell(out)/1024);
ERR:    
    if (in) fclose(in);
    if (out) fclose(out);
    return ret;
}


void usage(void)
{
    fprintf(stdout, 
        "scrs -ファイル偽装変換-\n"
        "基本書式→scrs コマンド 引数\n"
        "エンコード: scrs e infile outfile\n"
        "デコード  : scrs d infile outfile\n"
    );
    exit(0);
}


int main(int argc, char **argv)
{
    int r;
    
    if (argc < 4) usage();
    switch (argv[1][0]) {
        case 'e':
        r = encode(argv[2], argv[3]);
        break;
        
        case 'd':
        r = decode(argv[2], argv[3]);
        break;
        
        default:
        usage();
    }
    return (r != 0 ? 0 : 1);
}

サブストリームに隠そうぜ![NTFS限定]

前々回、他のファイルに寄生させるという方法を書いたのですが、こちらはANSI準拠の関数しか使わないので、OSの垣根を超えた方法でした。 今回はNTFSのサブストリームに隠す方法を紹介します。だからWin2000とかXPとかのNT系でしか動かないはずです。 利点としては、

と、なかなかエロ画像隠蔽に便利そうなのですが、NTFSでしか使えない、 USBメモリとかフロッピーとかがFATの場合、持ち運ぶこともできない。 といった弱点もあります。

サブストリームの扱い方は非常に簡単で、WindowsのAPI(CreateFile,Wrete/ReadFile)を使って読み書きできます。 ファイル名を"ファイル名:ストリーム名"とするだけでOK。

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct {
	HANDLE hFBase;//入れるファイル
	HANDLE hFSub;//サブストリームに追加するファイル
} ERO;

int OpenX(ERO *pero, char *base, char *sub)
{
	char subname[500];//ファイル名+サブストリーム
	char nam[500], ext[500];
	
	_splitpath(sub, NULL, NULL, nam, ext);
	sprintf(subname, "%s:%s%s", base, nam, ext);
	
	pero->hFBase = CreateFile(subname, GENERIC_READ | GENERIC_WRITE, 
			FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (pero->hFBase == INVALID_HANDLE_VALUE) return FALSE;
	
	pero->hFSub = CreateFile(sub, GENERIC_READ | GENERIC_WRITE, 
			FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (pero->hFSub == INVALID_HANDLE_VALUE) {
		CloseHandle(pero->hFBase);
		return FALSE;
	}

	printf(
		"対象ファイル : %s\n"
		"ストリーム   : %s%s\n"
		, base, nam, ext);
	
	return TRUE;
}

void CloseX(ERO *pero)
{
	CloseHandle(pero->hFBase);
	CloseHandle(pero->hFSub);
}

int WriteX(ERO *pero)
{
	DWORD r, w, p=0;
	char buf[10000];
	
	printf("サブストリームに書き込み...\n");
	do {
		if (ReadFile (pero->hFSub , buf, 10000, &r, NULL) == FALSE) goto ERR;
		if (WriteFile(pero->hFBase, buf, r    , &w, NULL) == FALSE) goto ERR;
		p += r;
		printf("read : %8d \r", p);
	} while (r);
	printf("\n完了!\n");
	return TRUE;
ERR:
	printf("\nエラー!\n");
	return FALSE;
}

int ReadX(ERO *pero, char *out)
{
	DWORD r, w, p=0;
	char buf[10000];
	HANDLE hFOut;
	
	hFOut = CreateFile(out, GENERIC_READ | GENERIC_WRITE, 
			FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFOut == INVALID_HANDLE_VALUE) return FALSE;
	printf("サブストリームから読み込み...\n");
	printf("出力ファイル名 : %s\n", out);
	do {
		if (ReadFile (pero->hFBase, buf, 10000, &r, NULL) == FALSE) goto ERR;
		if (WriteFile(hFOut       , buf, r    , &w, NULL) == FALSE) goto ERR;
		p += r;
		printf("read : %8d \r", p);
	} while (r);
	printf("\n完了!\n");
	CloseHandle(hFOut);
	return TRUE;
	
ERR:
	printf("\nエラー!\n");
	CloseHandle(hFOut);
	return FALSE;
}

int DeleteX(char *f, char *s)
{
	char ff[500];
	sprintf(ff, "%s:%s", f,s);
	printf("削除 : %s", ff);
	return DeleteFile(ff);
}


void usage(void)
{
	const char *msg = 
		"erox ver1.1\n"
		"サブストリームにエロ画像を隠蔽する\n"
		"\n"
		"書き込み erox w 対象ファイル 書きこむファイル\n"
		"読み込み erox r 対象ファイル 読み込むストリーム [出力ファイル]\n"
		"削除     erox d 対象ファイル ストリーム名\n";
	
	printf("%s", msg);
	exit(0);
}



int main(int argc, char **argv)
{
	ERO e;
	
	if (argc < 4) usage();

	if (argv[1][0] == 'd') {
		DeleteX(argv[2], argv[3]);
		return 0;
	}
	
	if (OpenX(&e, argv[2], argv[3]) == FALSE) {
		printf("ファイルオープンエラー!\n");
		return 1;
		
	};
	if (argv[1][0] == 'r') {
		if (argc == 4) {
			ReadX(&e, argv[3]);
		} else {
			ReadX(&e, argv[4]);
		}
	} else if (argv[1][0] == 'w') {
		WriteX(&e);
	} 
	
	//ハンドルを閉じる
	CloseX(&e);
}

書きこむストリームはエロ画像のファイル名になる。 日本語ストリーム名がいけるかどうかは知らない。

バイナリとソース

使い方 今回もDOS窓専用。

書き込み erox w 対象ファイル 書きこむファイル
読み込み erox r 対象ファイル 読み込むストリーム [出力ファイル]
削除     erox d 対象ファイル ストリーム名

※
書きこむストリームはエロ画像のファイル名になる。
日本語ストリーム名がいけるかどうかは知らない。