目次

Cプログラム(bcc32)

コンパイル

なんかバージョン上がってて、configファイルとかいらないっぽかった。

Windowsプログラミングで、WinMainをエントリーポイントにするとき、基本的には以下

bcc32c -tW sorce.c

プログラムを起動させるEXE(Windows用)

例として、Javaとかやり始めた人は分かると思いますが、あのコマンドプロンプトの画面を出さずにプログラムを起動させたいのです!
(まあJavaに限ったことではないですが)そんなときに使えそうなEXEを作りました。
中身は、win32 API(Windows API)で設定ファイル記述のプログラムおよび引数を、まるっとCreateProcessするだけのプログラム。Cで書いたので.netとか必要ないはずです。
「javaw xxxxx.class args」とか使えます。Javaに限らずPythonとかでも…。これならコマンドプロンプトの画面が出ない!

ダウンロード:https://drive.google.com/open?id=0B8Aw9PUq8EW-TXZyU1Bpdm9ZZ1U

一般ユーザーで管理者実行させる

adminexec.zip

会社とかで情報関連の部署で管理とかしてると、管理者ユーザーでアプリケーション実行させたい場合が多々あります。そんなときのために作りました。一応ユーザー名とパスワードを暗号化(?)っぽいことをしているので一般の社員に管理者情報モロバレという事態がないようにしています。

powershellとかVBSとかで調べたけど、やっぱりWin32 APIたたかないとダメだった。VSはなんかライセンス的にダメっぽいようだし。 結局Embarcadero C++ Compiler (BCC32C) でやることに。C言語なんて数年ぶり。

zipで固めてまるっとUPします。半分捨てプログラムみたいなものなので好きに役立てて下さい。苦情などは受け付けませんのであしからず。

使い方

adminexec.exe /f <ユーザー情報ファイル> /e <実行コマンドのあるファイル>
adminexec.exe /f <ユーザー情報ファイル> /c <実行するコマンド>

使用例としては ファイルから実行するとき

adminexec.exe /f admin.usr /e cmdexe.app

コマンドを直接実行するとき

adminexec.exe /f admin.usr /c powershell -EcexutionPolicy Bypass -Command "start-process eudcedit.exe"

ユーザー情報ファイル(admin.usr)の中身

;行頭セミコロンはコメント行
;ユーザー名
szUserName=user
;ドメイン
szDomain=company.local
;パスワード
szPassword=userPassword

※ユーザー、パスワードは暗号化したものを入れて下さい。ドメイン行をコメントアウトしたり、なにも値を入れないと、ローカルにいるユーザーでの実行になるようです。

コマンドファイル(cmdexe.app)の中身の例

;実行コマンド
szAppCmd=powershell -EcexutionPolicy Bypass -Command "start-process eudcedit.exe"

[szXXXXXXXX=]各ファイルのこの部分は読込判定に使ってるので変更しない。[=]の前後にはスペース入れないこと。

コマンドについて、外字エディタの起動など、一部のアプリケーションで、素直に実行しても起動できない場合がある。そんなときはPowershell経由で実行すると良い。また、引数判定に「/」を使っているのでcmd.exe経由では実行出来ません。

コマンド実行出来ない入力例
C:\Windows\System32\eudcedit.exe

実行出来る例
powershell -EcexutionPolicy Bypass -Command "start-process eudcedit.exe"
notepad.exe "D:\Hello World.txt"

暗号化について

別途作ったango.exeで暗号化してます。とは言っても排他的論理和を用いたもので、プロからしてみればどうってことないと思われますが、ちょこっと分からなくする分にはちょうど良いと思います。

ango.exe <変換する文字列>

ここで変換した文字列を先のユーザー情報ファイルに貼り付けます。

コード

ango.h

#include<string.h>
void ango(char *cp){
	int key=0x11111111;
	for(int i=0;i<strlen(cp)&&i<256;i++)cp[i]=cp[i]^key;
}

ango.c

#include "ango.h"
int main(int argv, char *argc[]){
	char arg[256];
	if( argv != 2 ) return 1;
	memset(arg,'\0',256);
	strlen(argc[1])>255?strncpy(arg,argc[1],256):strncpy(arg,argc[1],strlen(argc[1]));
	ango(arg);
	printf("%s",arg);
	return 0;
}

adminexec.c

#include<windows.h>
#include<stdio.h>
#include<stdlib.h>
#include<locale.h>
#include "ango.h"

// ===========================================================================

// 引数関連の定数 それぞれ/f,/e,/cを格納するchar配列の番号
#define ADMINFILE 0
#define EXECFILE  1
#define CMD       2

// ===========================================================================

//管理者情報構造体 解放する
typedef struct {
	char    szUserName[64];
	char    szDomain[64];
	char    szPassword[64];

} Admin;

//コマンド格納構造体 解放する
typedef struct {
	char    szAppCmd[2048];
} App;

// ===========================================================================

/**
 直接入力されたコマンドを読み込む(/c)
 App *app			コマンド格納用構造体へのポインタ
 char *cmd			コマンド
*/
int Application_cmd(App *app, char *cmd){

	if( cmd == NULL ) return -1;

	lstrcpyn(app->szAppCmd, cmd, strlen(cmd)+1);

	return 0;
}
/**
 コマンドファイルを読み込む(/e)
 App *app			コマンド格納用構造体へのポインタ
 char *filePath		コマンドファイルのパス
*/
int Application(App *app, char *filePath){
	FILE *fp;
	char line[512];
	char tmp[512];
	char status[2][16] = {"szAppCmd="};

	if( (fp=fopen(filePath,"r")) == NULL ){
		sprintf(tmp,"コマンドファイルが読めませんでした。\n[%s]",filePath);
		MessageBox(NULL, tmp, "AppFile Not Read!",MB_OK);
		return -1;
	}

	while(fgets(line, sizeof(line), fp)){
		if(line[0]==';') continue;

		for(int i=0; i<1 ; i++){
			if( strstr(line,status[i]) ){
				int len = ( lstrlen(line) > 2047 )? 2047: lstrlen(line);
				lstrcpyn(tmp, line+lstrlen(status[i]), len);
				switch(i){
					case 0:
						lstrcpyn(app->szAppCmd, tmp, lstrlen(tmp));
						break;
					default:;
				}
				continue;
			}
		}
	}
	fclose(fp);

	return 0;
}

/**
 管理者情報ファイルを読み込む
 Admin *admin		管理者情報格納用構造体へのポインタ
 char *filePath		管理者情報ファイルのパス
*/
int Administrator(Admin *admin, char *filePath){
	FILE *fp;
	char line[512];
	char tmp[512];
	char status[3][16] = {"szUserName=", "szDomain=", "szPassword="};

	if( (fp=fopen(filePath,"r")) == NULL ){
		sprintf(tmp,"管理者情報ファイルが読めませんでした。\n[%s]",filePath);
		MessageBox(NULL, tmp, "AdminFile Not Read!",MB_OK);
		return -1;
	}

	while(fgets(line, sizeof(line), fp)){
		if(line[0]==';') continue;

		for(int i=0; i<3 ; i++){
			if( strstr(line,status[i]) ){
				int len = ( strlen(line) > 63 )? 33: lstrlen(line);
				lstrcpyn(tmp, line+lstrlen(status[i]), len);
				switch(i){
					case 0:
						lstrcpyn(admin->szUserName, tmp, lstrlen(tmp));
						break;
					case 1:
						lstrcpyn(admin->szDomain, tmp, lstrlen(tmp));
						break;
					case 2:
						lstrcpyn(admin->szPassword, tmp, lstrlen(tmp));
						break;
					default:;
				}
				continue;
			}
		}

	}
	fclose(fp);

	return 0;
}


// ===========================================================================

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	STARTUPINFO         sInfo;
	PROCESS_INFORMATION pInfo;

	// 引数格納用 ----------------------------------------
	char              args[3][2048];
	char              *ag;

	//char->WCHAR変換用 ----------------------------------
	WCHAR              szWTmp1[128] , szWTmp2[128] , szWTmp3[128] ;
	WCHAR              szWTmp4[1024] ;

	// 管理者情報ファイルとコマンドファイル
	Admin ad; // /f の引数が入る
	App   ap; // /e の引数が入る

	//引数処理 -------------------------------------------
	// こういう引数文字列を処理する
	// adminexec.exe /f xxxxxxxx /e xxxxxxxx
	ag=lpszCmdLine;
	while( *ag != '\0'){
		if(*ag=='/'){
			int  AryNum;
			int  agCnt=0;

			ag++;
			switch(*ag){
				case 'f': AryNum = ADMINFILE; break;
				case 'e': AryNum = EXECFILE ; break;
				case 'c': AryNum = CMD      ; break;
				default : AryNum = -1;
			}

			if( AryNum < 0 ) break;

			//ポインタを動かして行って引数先頭を求める
			ag++;
			while( *ag == ' '){ ag++; }

			//引数全体の長さを求める
			while( *(ag+agCnt)!='/' && (ag+agCnt)!='\0' ){ agCnt++; }

			//末尾スペース対策
			while( *(ag+agCnt-1)==' ' ){ agCnt--; }

			//引数部分をコピーする
			lstrcpyn(args[AryNum], ag, agCnt+1);

			//引数にした値長だけポインタを移動させる
			ag+=agCnt;
		} else {
			ag++;
		}
	}

	if( args[ADMINFILE]==NULL || (args[EXECFILE]==NULL && args[CMD]==NULL) ){
		MessageBox(NULL, "引数が指定されていません","No Args!",MB_OK);
		return 0;
	}

	//引数からファイルのデータやコマンドを構造体にセットする -----------------
	if( Administrator(&ad, args[ADMINFILE]) != 0 ){
		MessageBox(NULL, "Administrator Dataset Failed","Dataset_1",MB_OK);
		return 0;
	}
	if( args[EXECFILE] == NULL ){
		if(Application_cmd(&ap, args[CMD]) != 0 ){
			MessageBox(NULL, "Command Dataset Failed","Dataset_2",MB_OK);
			return 0;
		}
	} else {
		if(Application(&ap, args[EXECFILE]) != 0 ){
			MessageBox(NULL, "CmdFile Dataset Failed","Dataset_3",MB_OK);
			return 0;
		}
	}

	//初期化等 -------------------------------------------
	ZeroMemory(&sInfo,sizeof(STARTUPINFO));
	sInfo.cb = sizeof(STARTUPINFO);
	ZeroMemory(&pInfo,sizeof(PROCESS_INFORMATION));
	memset(szWTmp1,'\0',sizeof(szWTmp1)); memset(szWTmp2,'\0',sizeof(szWTmp2));
	memset(szWTmp3,'\0',sizeof(szWTmp3)); memset(szWTmp4,'\0',sizeof(szWTmp4));

	// 復号化 管理者のID・パスワードは暗号化している(はず)ので元に戻す
	ango(ad.szUserName);
	ango(ad.szPassword);

	//char->wchar変換 CreatePrecessWithLongWはwchar型しか受け付けないっぽいので変換
	setlocale(LC_CTYPE, "JPN");
	mbstowcs(szWTmp1, ad.szUserName, sizeof(szWTmp1));
	mbstowcs(szWTmp2, ad.szDomain  , sizeof(szWTmp2));
	mbstowcs(szWTmp3, ad.szPassword, sizeof(szWTmp3));
	mbstowcs(szWTmp4, ap.szAppCmd  , sizeof(szWTmp4));

	if(!CreateProcessWithLogonW(szWTmp1, szWTmp2, szWTmp3, 0, NULL, szWTmp4, 0, NULL, NULL, &sInfo, &pInfo))
	{
		if(GetLastError() == ERROR_ACCESS_DENIED){
			MessageBox(NULL, "アクセス拒否", NULL, MB_ICONWARNING);
		}
		else{
			MessageBox(NULL, "プロセス作成失敗!\nファイルやコマンドを確認してください。", NULL, MB_ICONWARNING);
		}
		
		return 0;
	}

	CloseHandle(pInfo.hThread);
	CloseHandle(pInfo.hProcess);

	return 0;
}