合計 昨日 今日

アバター
Dixq (管理人)
管理人
 
記事: 1535
登録日時: 2010年10月12日(火) 20:16
お住まい: 北海道札幌市
日記: 日記を見る (567)
日記
- 11月 2017
アンパンマンとバナナ (0)
   2017年11月16日(木) 23:28

+ 10月 2017
+ 9月 2017
+ 8月 2017
+ 7月 2017
+ 6月 2017
+ 5月 2017
+ 4月 2017
+ 3月 2017
+ 2月 2017
+ 1月 2017
+ 12月 2016
+ 11月 2016
+ 10月 2016
+ 9月 2016
+ 8月 2016
+ 7月 2016
+ 6月 2016
+ 5月 2016
+ 4月 2016
+ 3月 2016
+ 2月 2016
+ 1月 2016
+ 12月 2015
+ 11月 2015
+ 10月 2015
+ 9月 2015
+ 8月 2015
+ 7月 2015
+ 6月 2015
+ 5月 2015
+ 4月 2015
+ 3月 2015
+ 2月 2015
+ 1月 2015
+ 12月 2014
+ 11月 2014
+ 10月 2014
+ 9月 2014
+ 8月 2014
+ 7月 2014
+ 6月 2014
+ 5月 2014
+ 4月 2014
+ 3月 2014
+ 2月 2014
+ 1月 2014
+ 12月 2013
+ 11月 2013
+ 10月 2013
+ 9月 2013
+ 8月 2013
+ 7月 2013
+ 6月 2013
+ 5月 2013
+ 4月 2013
+ 3月 2013
+ 2月 2013
+ 1月 2013
+ 12月 2012
+ 11月 2012
+ 10月 2012
+ 9月 2012
+ 8月 2012
+ 7月 2012
+ 6月 2012
+ 5月 2012
+ 4月 2012
+ 3月 2012
+ 2月 2012
+ 1月 2012
+ 12月 2011
+ 11月 2011
+ 10月 2011
+ 9月 2011
+ 8月 2011
+ 7月 2011
+ 6月 2011
+ 5月 2011
+ 4月 2011
+ 3月 2011
+ 2月 2011
+ 1月 2011
+ 12月 2010
+ 11月 2010
+ 10月 2010
フォロー
カテゴリー
日常
1 記事

改竄されない変数の作り方

パーマリンクby Dixq (管理人) on 2017年5月04日(木) 03:16

龍神録でお金の金額を改竄されるので
http://dixq.net/g/h_10.html
変数を常に排他的論理和でXOR暗号化していました。
しかしそれだけでは突破されてしまいました。

なので今回はint型の代わりにEncryptedIntで変数を保持するようにしました。
EncryptedIntクラスの中身はこのようになっています。
演算子オーバーロード部は省略していますが、普通のint型と同じように使えます。

ただし変数に値を代入するたびに変数のアドレスが変わりますので改竄を難しくしてあり
リンク先のような「スペシャルねこまんま57号」で値を絞っていくような方法には効果的だと思っています。

コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
#pragma once
class EncryptedInt
{
    int* value;
public:
    EncryptedInt();
    void set(int value);
    int  get();
};

コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "EncryptedInt.h"
#include <DxLib.h>
 
const static int KEY = 0x0123'4567'89AB'CDEF; //XOR暗号キー'
 
EncryptedInt::EncryptedInt()
{
    value = new int;
    *value = 0 ^ KEY;
}
 
EncryptedInt::~EncryptedInt()
{
    delete value;
}
 
void EncryptedInt::set(int v)
{
    int n = GetRand(3000); //適当にnew繰り返す分
    int** pool = new int*[n];
 
    int tmp = *value;
 
    for (int i = 0; i<n; i++) {
        pool[i] = new int;
    }
 
    delete value;
    value = new int;
    *value = v ^ KEY;
 
    for (int i = 0; i<n; i++) {
        delete pool[i];
    }
    delete[] pool;
}
 
int EncryptedInt::get()
{
    return (*value) ^ KEY;
}


思いつきではこれくらいですが、演算子オーバーロードして普通のint型として使えるようにしておけば
改竄されたくない値は全部これ使えばいいってことになりますね。
で、安全性を高めたいんですが、もっと解析が困難になる方法ありませんかね?
最後に編集したユーザー Dixq (管理人) [ 2017年5月04日(木) 03:17 ], 累計 1 回

コメント数: 9 閲覧数: 5118
コメント

Re: 改竄されない変数の作り方

パーマリンクby usao on 2017年5月04日(木) 10:13

素人丸出しな感想文ですが…

・EncryptedInt → より細かく, EncryptedByte * 4個 とか,EncryptedBit * 32個 とかに?
・誤り訂正(というか検出)符号的なやつ(*N個)を,同じようにEncryptedIntで別に持つ?

みたく,複数のアドレスを同時に改ざんしなきゃいけなくなるような方向はどうなんでしょう.

あと,3進数表記文字列で保有するとかしたら効果ありますか?
アバター
usao
 
記事: 1313
登録日時: 2013年5月16日(木) 11:36
日記: 日記を見る (131)

Re: 改竄されない変数の作り方

パーマリンクby 御津凪 on 2017年5月04日(木) 11:32

そもそもの改竄用ツールを起動されていればゲームが立ち上がらない(もしくは正しく動かせない)ようにする二段構えという手はどうでしょうか?
UE4の無料プラグインにSCUE4でそういった機能を持たせていて、ソースコードもあります(UE4のライセンスに従って参考にする必要がありますが)
This article was written by "Mitsunagi".
アバター
御津凪
管理人
 
記事: 174
登録日時: 2010年10月13日(水) 00:18
お住まい: 道内
日記: 日記を見る (53)

Re: 改竄されない変数の作り方

パーマリンクby Dixq (管理人) on 2017年5月04日(木) 12:08

> usaoさん

なるほど、EncryptedByte * 4個でEncryptedIntをなすって考え方いいですね。
より解析が難しくなりそうです。

誤り訂正はMD5的なハッシュ値を持っておけば良さそうですね。
龍神録1も同じ要領で改竄を発見し、改竄を発見したらセーブデータをロックする仕組みにしています。
ここまですればフリーゲームとしてはかなり頑張ってる方じゃないでしょうか。

ありがとうございます。
アバター
Dixq (管理人)
管理人
 
記事: 1535
登録日時: 2010年10月12日(火) 20:16
お住まい: 北海道札幌市
日記: 日記を見る (567)

Re: 改竄されない変数の作り方

パーマリンクby Dixq (管理人) on 2017年5月04日(木) 12:11

> みつなぎさん

なるほど、別の角度からもガードするという発想もありですね。
Github見てみましたけどこれ解読するの骨が折れそう・・。
これって不正ツールじゃないツールがウォッチしているの誤認識したりしないんですかね?
例えばDxtoryやBandicam等で龍神録の画面を録画中だとか。
アバター
Dixq (管理人)
管理人
 
記事: 1535
登録日時: 2010年10月12日(火) 20:16
お住まい: 北海道札幌市
日記: 日記を見る (567)

Re: 改竄されない変数の作り方

パーマリンクby 御津凪 on 2017年5月04日(木) 13:58

Dixq (管理人) さんが書きました:これって不正ツールじゃないツールがウォッチしているの誤認識したりしないんですかね?
例えばDxtoryやBandicam等で龍神録の画面を録画中だとか。

比較的簡素な判定をしているようなので(Process名・WindowClass名やウィンドウタイトル名など)、その辺りを真似すれば(ある程度と念をいれますが)対応できますね。

後はゲーム起動をワンクッション置く形で(起動用実行ファイルから)CreateProcess関数のセキュリティ記述子の引数を外部からのアクセスを禁止する設定をしてゲームを起動すればより強固に出来るかと思われます。(もちろん直接ゲーム本体を起動されないようにプログラムする必要も出てきますが)
This article was written by "Mitsunagi".
アバター
御津凪
管理人
 
記事: 174
登録日時: 2010年10月13日(水) 00:18
お住まい: 道内
日記: 日記を見る (53)

Re: 改竄されない変数の作り方

パーマリンクby YuO on 2017年5月04日(木) 23:01

ReadProcessMemory/WriteProcessMemoryを弾ければだいたいの問題が解決するので,SetSecurityInfoを呼び出して,プロセスオブジェクトのDACLで自身とBULITIN\Administrators (S-1-5-32-544) を拒否してみましたが……。

昇格されたプロセスからのアクセスを拒否できませんでした。
Administratorsからアクセスを拒否できないのは仕方が無い面もありますが,ちょっと腑に落ちません……。
YuO
 
記事: 896
登録日時: 2010年12月01日(水) 01:25
お住まい: 東京都世田谷区
日記: 日記を見る (33)

Re: 改竄されない変数の作り方

パーマリンクby Dixq (管理人) on 2017年5月05日(金) 01:00

みつなぎさん

なるほど、その辺摸索してみます。
アバター
Dixq (管理人)
管理人
 
記事: 1535
登録日時: 2010年10月12日(火) 20:16
お住まい: 北海道札幌市
日記: 日記を見る (567)

Re: 改竄されない変数の作り方

パーマリンクby Dixq (管理人) on 2017年5月05日(金) 01:06

YuOさん

おぉ、非常に参考になる情報ありがとうございます。
拒否できなくてもメモリが書き換えられたということは分かるのでしょうか?
アバター
Dixq (管理人)
管理人
 
記事: 1535
登録日時: 2010年10月12日(火) 20:16
お住まい: 北海道札幌市
日記: 日記を見る (567)

Re: 改竄されない変数の作り方

パーマリンクby YuO on 2017年5月07日(日) 01:21

Dixq (管理人) さんが書きました:拒否できなくてもメモリが書き換えられたということは分かるのでしょうか?

できないです。

ReadProcessMemoryする権限を他のプロセスが要求した場合にOpenProcessが失敗すればReadProcessMemoryできないよね,
というのがDACLによる拒否の基本的な発想なので,メモリが書き換えられた,などを検出しようとはしていません。
御津凪さんが
御津凪 さんが書きました:後はゲーム起動をワンクッション置く形で(起動用実行ファイルから)CreateProcess関数のセキュリティ記述子の引数を外部からのアクセスを禁止する設定をしてゲームを起動すればより強固に出来るかと思われます。(もちろん直接ゲーム本体を起動されないようにプログラムする必要も出てきますが)

と書かれている方法も,発想は同じだと思います。
起動時のセキュリティ記述子のDACLの設定で最初から拒否するか,起動後に自身のセキュリティ記述子のDACLを修正して途中から拒否するか,の違いになります。
Offtopic :
起動時からDACLが拒否している場合にAdministratorsからアクセス不可かは試していないです。
理論上は同じなのですが……


メモリの書き込みの検出は……デバッガAPIを駆使すればできそうな気がするのですが,該当するものを見つけられませんでした。
# データブレークポイントを実現できればよい気がするのですが,方法がわからない……。
YuO
 
記事: 896
登録日時: 2010年12月01日(水) 01:25
お住まい: 東京都世田谷区
日記: 日記を見る (33)

オンラインデータ

登録ユーザー: みけCAT