20200601のC#に関する記事は9件です。

c# posgre 接続 createdb

Program.cs
using System;
using Npgsql;

namespace db02
{
    class Program
    {
        static void Main(string[] args){

        //接続文字列
        NpgsqlConnection conn = new NpgsqlConnection("Server=localhost;Port=5432;User ID=postgres;Database=postgres;Password=Chatdb01;Enlist=true");

            conn.Open();
            try {
                NpgsqlCommand command = new NpgsqlCommand("DROP DATABASE IF EXISTS test01", conn);
                command.ExecuteNonQuery();
                command = new NpgsqlCommand("CREATE DATABASE test01", conn);
                command.ExecuteNonQuery();
                string comment = "'Test Database " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss") + "'";
                command = new NpgsqlCommand("COMMENT ON DATABASE test01 IS " + comment, conn);
                command.ExecuteNonQuery();
            } finally {
                conn.Close();
            }

            conn = new NpgsqlConnection("Server=localhost;Port=5432;User ID=postgres;Database=test01;Password=Chatdb01;Enlist=true");
            conn.Open();
            try {
                NpgsqlCommand command = new NpgsqlCommand("select version()", conn);
                command.ExecuteNonQuery();
                var serverversion = (String)command.ExecuteScalar();
                Console.WriteLine("PostgreSQL server version: {0}", serverversion);
            } finally {
            conn.Close();
            }
        }
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

c# posgre 接続 select


using System;
using Npgsql;

namespace db01
{
    class Program
    {
        static void Main(string[] args){
            //接続文字列
            NpgsqlConnection conn = new NpgsqlConnection("Server=localhost;Port=5432;User ID=postgres;Database=postgres;Password=Chatdb01;Enlist=true");
            //PostgreSQLへ接続
            conn.Open();


            NpgsqlCommand cmd = new NpgsqlCommand("select version()", conn);
            var serverversion = (String)cmd.ExecuteScalar();

            Console.WriteLine("PostgreSQL server version: {0}", serverversion);
            conn.Close();
        }
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Prism.Wpf 7.2でプログレスバーのついたダイアログを作る

はじめに

 Prismを使ってプログレスバーの付いたダイアログを作りました。
 進捗の値0~100をダイアログに送り、100のときにダイアログを閉じることができるという仕様にしました。

prism2.gif

環境

.Net Core 3.1
Prism.Wpf 7.2.0.1422

実装

View

xaml.png

ProgressDialog.xaml
<UserControl x:Class="Module1.Views.ProgressDialog"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Module1.Views"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             Height="100"
             Width="200"
             mc:Ignorable="d" 
             xmlns:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True"
             xmlns:viewModels="clr-namespace:Module1.ViewModels"
             d:DataContext="{d:DesignInstance viewModels:ProgressDialogViewModel}">
    <prism:Dialog.WindowStyle>
        <Style TargetType="Window">
            <Setter Property="ResizeMode" Value="NoResize"/>
            <Setter Property="ShowInTaskbar" Value="False"/>
            <Setter Property="SizeToContent" Value="WidthAndHeight"/>
            <Setter Property="WindowStyle" Value="None"/>
            <Setter Property="BorderThickness" Value="1"/>
        </Style>
    </prism:Dialog.WindowStyle>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <WrapPanel Margin="10,15">
            <Label Width="30" HorizontalContentAlignment="Right" Content="{Binding Progress}"/>
            <ProgressBar Height="15" Width="130" Value="{Binding Progress}" />
        </WrapPanel>
        <Button Grid.Row="1" Height="20" Width="100" VerticalAlignment="Bottom" Margin="0,12" Content="閉じる" Command="{Binding CloseCommand}"/>
    </Grid>
</UserControl>

 ダイアログ用にプログレスバーと閉じるボタンが付いたViewを作成します。
 prism:Dialog.WindowStyleタグでダイアログとして呼び出された際のWindowStyleを制御しています。今回はできるだけダイアログを閉じられたくなかったのでWindowStyleNoneを指定しウィンドウの閉じるボタンを非表示にしています。

ViewModel

ProgressDialogViewModel
    public class ProgressDialogViewModel : BindableBase, IDialogAware
    {
        private int progress;

        public event Action<IDialogResult> RequestClose;

        public int Progress
        {
            get { return progress; }
            set { SetProperty(ref progress, value); }
        }

        public DelegateCommand CloseCommand { get; }

        public string Title => "Dialog1";

        public ProgressDialogViewModel(ProgressDialogModel model)
        {
            this.Progress = model.Progress;

            model.PropertyChanged += (_, e) =>
            {
                if (e.PropertyName == "Progress")
                {
                    this.Progress = model.Progress;
                }
            };

            this.CloseCommand =
                new DelegateCommand
                (
                    () => this.CloseDialog(),
                    () => this.Progress >= 100
                )
                .ObservesProperty(() => this.Progress);
        }

        public bool CanCloseDialog() => true;

        public void OnDialogClosed() => this.Progress = 0;

        public void OnDialogOpened(IDialogParameters parameters) { }

        private void CloseDialog()
            => RequestClose?.Invoke(new DialogResult(ButtonResult.OK));
    }

 ViewModelではViewのプログレスバーにバインドする項目としてProgressプロパティを定義しています。
 CloseCommadではダイアログを閉じるときの動作を担当しています。使用可否条件としてProgressの値が100以上であることを指定しています。
 ダイアログとして利用するためにIDialogAwareを実装しています。

Model

ProgressDialogModel
    public class ProgressDialogModel : BindableBase
    {
        private int progress;

        public int Progress
        {
            get { return progress; }
            set { SetProperty(ref progress, value); }
        }

        public ProgressDialogModel(IEventAggregator eventAggregator)
        {
            this.Progress = 0;

            eventAggregator
                .GetEvent<ProgressMessage>()
                .Subscribe(x => this.Progress = x);
        }
    }
ProgressMessage
    public class ProgressMessage : PubSubEvent<int>
    {
    }

 ModelではViewModelとバインドする項目としてProgressプロパティを定義しています。
 外部からの値受け取りはIEventAggregatorを介して行うものとしProgressMessageが発行されたときにProgressの値が変化するようにしています。

Module

Module1Module
    public class Module1Module : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
            _ = containerProvider.Resolve<ProgressDialogModel>();
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterSingleton<ProgressDialogModel>();
            containerRegistry.RegisterDialog<ProgressDialog>();
        }
    }

 Moduleでは他のプロジェクトでダイアログを利用できるようDIコンテナにViewとModelを登録しています。ModelはシングルトンとしてDIコンテナに登録しました。

ダイアログ呼び出し部分

        public DelegateCommand ShowDialogCommand { get; }

        public MainWindowViewModel(IDialogService dialogService, IEventAggregator eventAggregator)
        {
            this.ShowDialogCommand =
                new DelegateCommand(() =>
                {
                    _ = Task.Run(async () =>
                    {
                        eventAggregator.GetEvent<ProgressMessage>().Publish(0);
                        await Task.Delay(1000);
                        eventAggregator.GetEvent<ProgressMessage>().Publish(33);
                        await Task.Delay(1000);
                        eventAggregator.GetEvent<ProgressMessage>().Publish(66);
                        await Task.Delay(1000);
                        eventAggregator.GetEvent<ProgressMessage>().Publish(100);
                    })
                    .ContinueWith(x => x.Exception /* エラー処理 */, TaskContinuationOptions.OnlyOnFaulted);

                    dialogService.ShowDialog(nameof(ProgressDialog), new DialogParameters(), null);
                });
        }

 ダイアログのプロジェクトとは別の画面を作り、そのViewModelにShowDialogCommandというダイアログの動作確認をするためのコマンドを用意しました。
 ShowDialogCommandでは、非同期処理呼び出しとダイアログ呼び出しの2つを実行しています。
 非同期処理では処理中にIEventAggregatorを介してProgressMessageを発行しModelに進捗を表す数値を送っています。ここでは1秒間隔でModelの進捗の値を変更しています。ContinueWithの第一引数部分には非同期処理でエラーになった際の処理を書く予定です。
 ダイアログ呼び出しはIDialogServiceShowDialogを使って定義したダイアログを呼び出しています。

おわりに

 プログレスバーの付いたダイアログを作ることができました。他の画面から呼び出せることとプログレスバーの値を処理の進み具合によって制御できることを確認できました。

・ソースコード
https://github.com/ttlatex/PrismProgressDialog

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#変数(値型)について

C#変数(値型)
値型には2種類ある
・データと関連機能をカプセル化する構造体の型
・名前付き定数のセットによって、定義され、選択しまたは選択肢の組み合わせを表す列挙型。

組み込みの値型

⇒単純型とも呼ばれる組み込み値型が用意されています。
・整数数値型
・有働小数点数値型
・ブール値を表すbool
・Unicode UTF-16文字を表すchar

構造体の型
データおよび関連する機能をカプセル化できる値型。構造体型を定義するには、structキーワードを使用。
(つまり関連する項目を一つの塊にしたもの)

構造体はint型や文字列など型の違うモノでも一つの塊にできる。
(処理を定義することもできるのでクラスと似ている)

共通点 違い 構造体 クラス
インスタンス化して使用 オブジェクトの型 値型 参照型
使用する際にインスタンス化する クラスの継承 不可 可能
メソッドの定義 フィールドの初期化子の使用 不可 可能
フィールド(メンバ変数)だけではなく、メソッドを定義して処理を行う デフォルトコンストラクタ 不可 可能
引数ありコンストラクタの定義 デストラクタの定義 不可 可能
インスタンス化してフィールドの値を初期化する場合に使用
インターフェースの実装
インターフェースの実装(複数可)

構造体の定義
キーワードstructを使って以下のように定義。

    [修飾子]struct 構造体名
    {
        フィールド(メンバ変数);
    }

例えば2次元の座標を扱う場合は

    public struct Test
    {
        public int a;
        public int b;
    }

コンストラクタの定義
構造体では引数ありのコンストラクタの定義ができる
例:

public struct Test
{
    public int a;
    public int b;

    public Test(int a, int b){
        this.a = a;
        this.b = b;
    }
}

メソッドの定義
例:

public struct Sample
{
    public double d;

    public Sample(double dr){
        d = dr;
    }

    public double SampleA(double r){
        return 3.14 * r;
    }

    public double SampleArea(double r){
        return 3.14 * r * r;
    }
}

構造体を定義す売る際の注意点
・構造体のフィールドは初期化子を使用できない!
・引数なしのコンストラクタを定義できない!

参考資料:
・C#の絵本
・Microsoft Build
・Wikipedia

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Raspberry Pi C#でLチカ

マイクロソフト製のGPIOライブラリを使う

https://github.com/dotnet/iot

呼び出し方

using System.Device.Gpio;

GitにC#で書かれたLチカサンプルソースがあるので利用します。

サンプルソース

RaspberryPiにNetCore 3.1をインストール

LinuxのArmのところをクリックします
スクリーンショット 2020-06-01 17.27.58.png

.net core sdk DownLoadPage

クリックした次に画面でパスをコピペできるのでパスを取得します
スクリーンショット 2020-06-01 17.13.58.png

$ wget パス

.NET Core SDK をインストールする

$ mkdir -p $HOME/dotnet && tar zxf dotnet-sdk-3.1.100-linux-x64.tar.gz -C $HOME/dotnet

$ vim ~/.bashrc
#パスを追加する
export DOTNET_ROOT=$HOME/dotnet
export PATH=$PATH:$HOME/dotnet

dotnetをパスを通します

VisualStudioMacでコンソールアプリの開発

スクリーンショット 2020-06-01 17.02.26.png
.net Coreを選択
スクリーンショット 2020-06-01 17.02.35.png

NugetからSystem.Device.Gpioを取得

MicroSoft製のGpioライブラリをダウンロードします
スクリーンショット 2020-06-01 17.01.24.png

using System;
using System.Device.Gpio;
using System.Threading;

namespace led {
    class Program {
        static void Main(string[] args) {
       //GPIOを番号を指定すること
            int pin = 7;
            GpioController controller = new GpioController();
            controller.OpenPin(pin, PinMode.Output);

            int lightTimeInMilliseconds = 1000;
            int dimTimeInMilliseconds = 200;

            while(true) {
                Console.WriteLine($"Light for {lightTimeInMilliseconds}ms");
                controller.Write(pin, PinValue.High);
                Thread.Sleep(lightTimeInMilliseconds);
                Console.WriteLine($"Dim for {dimTimeInMilliseconds}ms");
                controller.Write(pin, PinValue.Low);
                Thread.Sleep(dimTimeInMilliseconds);
            }
           }
      }
}

ビルド

dllを指定すると実行できます。exeに出力するやり方もあります。

$ dotnet led.dll

ポイント

controller.OpenPin(pin, PinMode.Output) はGPIOを番号すること
スクリーンショット 2020-06-01 17.05.29.png

課題

リモートGPIOについて調べる

VisualStudioMacで作成したプロジェクトファイルをMonoDevelopで開きデバッグする

MoNoDevelopにSDKのパスを設定する
スクリーンショット 2020-06-01 17.04.46.png

C#でのLチカ動作確認とれました。

PythonでLチカ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Visual Studio 2019 のデバッガーでメソッドの戻り値見たいんですが

やってしまった。

以下のようなツイートをしたのですが

そういえば Visual Studio でデバッグしてて、メソッドの最後の閉じ括弧にいるときは 
$returnvalue をウォッチ式として入れると戻り値が見れるという豆知識

まゆき先生に指摘されたのですが間違ってました orz

$returnvalue はステップオーバーなどで実行したメソッドの戻り値が入ってるということなので、私の閉じ括弧の位置では、まだ戻り値は入っていませんでした。

私のコードだと、ToArray して暗黙の型変換されたものを return してたので return の結果と一致してただけでした。残念 orz

ということで、じゃぁメソッドの戻り値見たい場合は、どうすればいいの?ということですが、軽く見た感じ上記ツイートの位置にブレークポイントがある時点では無理っぽいです。

return 文に書いてある式に副作用が無いケースでは以下のように return から先を選択して Shift + F9 のクイック ウォッチで確認することも出来ます。

image.png

副作用がある場合はおとなしくステップオーバーをしてメソッドから抜けます。
メソッドから抜けると、メソッドの戻り値を変数に入れていない場合でも自動変数に結果が表示されます。自動変数を見たい場合はデバッグ中にメニューの「デバッグ」→「ウィンドウ」→「自動変数」で表示されるウィンドウで見れます。

image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

僕が考えた最強の.NETアプリケーション保護と.NETの仕組みを徹底解説

最強の.NETアプリケーション保護を考えた

こんにちは。
色々とQuiitaでプロジェクトをすすめていましたが、例のウイルスによってなかなか更新するタイミングが見つけられませんでした(T_T)

そんななかC#で書かれた.NETアプリケーションの最強の保護を考えてみました。
そもそも、なぜ.NETアプリケーションを保護する必要があるかと言いますと..
簡単に言えばエンジニアでなくとも、簡単にコードの閲覧や改竄ができてしまうからです。何も技術的な知識が無くとも、です。

shinpai_man.pngうーん、何故だろう?

なぜ保護が必要?

Dnspyという便利なソフトウェアがあり、.NETアプリケーションexecutableを放り込むだけで容易にソースコードの閲覧や改竄が可能です。
もちろん、この他にも様々な方法で同じようなことを行うことが出来ます。

例として以下のようなコードを書いてみました。

static void Main(string[] args)
{
    var この変数は絶対秘密っ = "HImitsu";
    var result = new StringBuilder();

    for (var x = 0; x < この変数は絶対秘密っ.Length; x++)
    {
        switch(この変数は絶対秘密っ[x])
        {
            case 'H':
                result.Append("A");
                break;
            case 'I':
                result.Append("B");
                break;
            case 'm':
                result.Append("C");
                break;
            case 'i':
                result.Append("D");
                break;
            case 't':
                result.Append("E");
                break;
            case 's':
                result.Append("F");
                break;
            case 'u':
                result.Append("G");
                break;
        }
    }

    Console.WriteLine(result);
    Console.ReadKey();
}

これをdnspyに放り込むだけで、
image.png
このようにリバースエンジニアリングが容易であることから、セキュリティリスクは避けられません。

もちろん適材適所という言葉もございますが、再頒布する前提の業務アプリケーション等は特にセキュリティには気を配るべきであって、絶対に生のままリリースするといったことがあってはならないと思っています。
pose_ukkari_man.pngえっ、何で・・・?

なぜリバースエンジニアリングが簡単?

それでは本題にうつる前に、なぜ.NETアプリケーションがこんなにも容易にリバースエンジニアリングできてしまうのかを考えてみましょう。
まず、.NET FrameworkはCLR (Common Language Runtime)という共通言語ランタイムによって実行されます。
そしてそのCLRはJavaの仮想環境のような振る舞いをすると考えていただいて問題ありません。(ちょっと違いますが)
ということは、そうです。Javaも簡単にリバースエンジニアリングすることができます。

.NET Frameworkで作成されたアプリケーションをコンパイルすると、MSIL(Microsoft Intermediate Language)という中間コードに変換されます。
そして、その中間コードがJIT (Just In Time) Compilerによって実行時にネイティヴコードに変換されるのです。
Untitled Diagram (1).png
kotowaza_mekara_uroko_man.pngなるほど、コードはexecutableに中間言語としてバイナリ化されているのじゃな!
pistol_pose_man.pngへへっ。甘いね。俺には「難読化」という高度な手段があるから安心だぜ。

難読化のメリットとデメリット

programming.png
こういったセキュリティリスクを避ける為に使われるのがコードの「難読化」という手段で、一番ポピュラーな保護方法です。
しかし、その「難読化」は本当に安全と言えますか?
答えは「Absolutely NO!」です。

インターネット上には様々な「Unpacker(アンパッカー)」と呼ばれる難読化解除ツールが存在し、これもまたエンジニアやプログラミングの知識をもった人間でなくとも、簡単に難読化を解除してしまうものが沢山あります。
ここで書くつもりはありませんが、僕がパッと思い浮かぶものだけで10個はありますね。そのくらい、難読化という保護の手段にさえもリスクが付きまとってきます。

さらに...相手が知識・経験と技術をもったハッカーだとしたら?更に危険です。
もはや「難読化」という手段はハッカーを一定時間足止めする"時間稼ぎ"でしかないでしょう。
pose_sugoi_okoru_woman.pngかーっ!じゃあどうしたらいいんだよ!界王拳20倍!

効果的な保護

それではここから実際にどのように効果的に.NETアプリケーションを保護するか、という本題に移ります。
簡単に言えばこの方法は「.NETをC++でホストする」です。
pose_nidomi2.pngそんなことできちゃうの!?
できちゃいます。
正確にはC++にてCLRをホスティングします。
religion_keiji_man.pngおお、神よ・・・コピペの準備は整いましたぞよ・・・

ネイティヴC++アプリケーションでホストしてみよう

先ず、保護したい.NETアプリケーションのバイナリをゲットしましょう。
ツールは何でも良いですが、僕の場合は簡単にコード化した状態で出力してくれる「HxD」という有名ツールを使用しました。
該当.NETアプリケーションを放り込んで、バイナリを全て選択した状態でFileCopy asCとすると以下のようなバイナリが出力されます。
日本語設定だとちょっと違うかも知れません。
6d3bfd39a0a180a8c5a65490a8064ab3.png
これを適当にヘッダーを作成した中に放り込んでおきます。
ここではfile.hとしました。

file.h
unsigned char rawData[5120] = {
    0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
    ...
}

次に...メインソースです。
インクルード・インポートは以下のようになります。
mscorlib.tlb%SystemRoot%\Microsoft.NET\Frameworkの適当バージョン内で見つかります。
また、インポート属性としてraw_interfaces_onlyを指定する必要があります。
raw_interfaces_onlyに関しては、僕もよく分かっていません。

rawインターフェースのみ定義する。
例えばReadyStateというプロパティーに対し、get_ReadyState()という関数だけ定義される。(通常のCOMインターフェースなんだそうだ)
この属性を指定しない場合は、GetReadyState()という関数も定義される。(特殊なラッパーなんだそうだ)
引用: http://www.ne.jp/asahi/hishidama/home/tech/vcpp/import.html

#include "stdafx.h"

#include <windows.h>
#include <metahost.h>

#include "file.h"

#pragma comment(lib, "mscoree.lib")
#import "mscorlib.tlb" raw_interfaces_only

いよいよメインコードです。
何をしているかについては、適時コード上のコメントアウトをご参照下さい。
僕のコメントアウトは全て環境移行時の文字化けを避ける為貧相な英語となっていますm(_)m
※コードの動作を理解するにはCOM(Component Object Model)の理解が必要です!

int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    ICLRMetaHost       *pMetaHost       = NULL;
    ICLRMetaHostPolicy *pMetaHostPolicy = NULL;
    ICLRDebugging      *pCLRDebugging   = NULL;

    /* Create an instance of CLR_METAHOST */
    if (FAILED(CLRCreateInstance(
        CLSID_CLRMetaHost, 
        IID_ICLRMetaHost, 
        reinterpret_cast<LPVOID*>(&pMetaHost)
    )))
    {
        MessageBox(NULL, TEXT("Couldn't create an instance of CLR_METAHOST."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* Create an instance of CLR_METAHOST_POLICY */
    if (FAILED(CLRCreateInstance(
        CLSID_CLRMetaHostPolicy, 
        IID_ICLRMetaHostPolicy, 
        reinterpret_cast<LPVOID*>(&pMetaHostPolicy)
    )))
    {
        MessageBox(NULL, TEXT("Couldn't create an instance of CLR_METAHOST_POLICY."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* Create an instance of CLR_DEBUGGING */
    if (FAILED(CLRCreateInstance(
        CLSID_CLRDebugging, 
        IID_ICLRDebugging, 
        reinterpret_cast<LPVOID*>(&pCLRDebugging)
    )))
    {
        MessageBox(NULL, TEXT("Couldn't create an instance of CLR_DEBUGGING."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* 
     * Get the runtime information with the version
     * Found at: "%SystemRoot%\Microsoft.NET\Framework"
     */
    ICLRRuntimeInfo* pRuntimeInfo = NULL; 
    if (FAILED(pMetaHost->GetRuntime(
        L"v4.0.30319", 
        IID_ICLRRuntimeInfo, 
        reinterpret_cast<void**>(&pRuntimeInfo)
    )))
    {
        MessageBox(NULL, TEXT("Failed to get the runtime."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* Check if the runtime is loadable */
    BOOL isLoadable;
    if (FAILED(pRuntimeInfo->IsLoadable(&isLoadable)) || !isLoadable)
    {
        MessageBox(NULL, TEXT("The runtime is not loadable."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* Get an interface pointer of the runtime host */
    ICorRuntimeHost* pRuntimeHost = NULL;
    if (FAILED(pRuntimeInfo->GetInterface(
        CLSID_CorRuntimeHost, 
        IID_ICorRuntimeHost, 
        reinterpret_cast<void**>(&pRuntimeHost)
    )))
    {
        MessageBox(NULL, TEXT("Failed to get the interface of CLR."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* Start the runtime host */
    if (FAILED(pRuntimeHost->Start()))
    {
        MessageBox(NULL, TEXT("Failed to start the runtime host."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* Get a pointer of the AppDomain thunk */
    IUnknownPtr pAppDomainThunk = NULL;
    if (FAILED(pRuntimeHost->GetDefaultDomain(&pAppDomainThunk)))
    {
        MessageBox(NULL, TEXT("Failed to get the default domain of runtime host."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* Get a pointer of the AppDomain interface */
    mscorlib::_AppDomainPtr pDefaultAppDomain = NULL;
    if (FAILED(pAppDomainThunk->QueryInterface(
        __uuidof(mscorlib::_AppDomain), 
        reinterpret_cast<void**>(&pDefaultAppDomain)
    )))
    {
        MessageBox(NULL, TEXT("QueryInterface Failed."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* Create a safe array */
    SAFEARRAYBOUND array[1];
    array[0].cElements = sizeof(rawData);
    array[0].lLbound   = 0;
    SAFEARRAY* pSafeArray  = SafeArrayCreate(VT_UI1, 1, array);
    if (!pSafeArray)
    {
        MessageBox(NULL, TEXT("Failed to create a safe array."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* Lock the array for safe access */
    void* pPvData = NULL;
    if (FAILED(SafeArrayAccessData(pSafeArray, &pPvData)))
    {
        MessageBox(NULL, TEXT("Failed to access to the safe array."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* Deploy our rawData into the memory. */
    memcpy(pPvData, rawData, sizeof(rawData));

    /* Unlock the array for safe access */
    if (FAILED(SafeArrayUnaccessData(pSafeArray)))
    {
        MessageBox(NULL, TEXT("Failed to destroy the access to the safe array."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* 
     * Load the assembly 
     * C#: System.AppDomain.CurrentDomain.Load(byte[] rawAssembly)
     */
    mscorlib::_AssemblyPtr pAssembly = NULL;
    if (FAILED(pDefaultAppDomain->Load_3(pSafeArray, &pAssembly)))
    {
        MessageBox(NULL, TEXT("Failed to load the assemblies."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* 
     * Get the entry point of the assembly 
     * C#: System.Reflection.Assembly GetEntryAssembly()
     */
    mscorlib::_MethodInfoPtr pMethodInfo = NULL;
    if (FAILED(pAssembly->get_EntryPoint(&pMethodInfo)))
    {
        MessageBox(NULL, TEXT("Failed to get the entry point of the assembly."), TEXT("Error"), MB_OK);
        return 1;
    }

    /* 
     * Invoke a method of the entry point 
     * C#: static void Main(string[] args)
     */
    VARIANT retVal, obj;
    obj.vt = VT_NULL;
    SAFEARRAY *pParameters = SafeArrayCreateVector(VT_VARIANT, 0, 0);
    if (FAILED(pMethodInfo->Invoke_3(obj, pParameters, &retVal)))
    {
        MessageBox(NULL, TEXT("Failed to invoke the method."), TEXT("Error"), MB_OK);
        return 1;
    }

    return 0;
}

これにて、ホストするC++側の準備は完了です!
実行すると、問題無く.NET Framework 4.7.2で動作するアプリケーションが起動しました。

次にやるべきこと

C・C++等の低レベル言語のリバースエンジニアリングは.NETやJava等と違い、遥かに困難となります。が!
ネイティヴC++アプリケーション側をリバースエンジニアリングしてみると、やはりまだまだセキュリティは甘そうです。
image.png
もちろん.NETアプリケーションのバイナリも丸見えで簡単に抜けますから、これでは全く意味が無いですね。
image.png
これではハッカーからの攻撃に対して十分な保護能力があるかというと、全くありません
hacker_cracker4_laugh.pngヨユーww
幾つかのスパイスを加えることでリバースエンジニアリングを更に困難にしましょう!

スパイス 概要 ハッキング難易度
VMProtect リソース保護やユーザモードからカーネルモードまでのデバッガ検出、仮想環境検出やソフトウェア保護に関する様々な機能を提供します。ホスト元であるC++アプリケーションexecutableを保護することで、効果覿面です!
※一応.NETアセンブリにも対応していますが、お世辞にも良い保護とは全く言えませんので絶対にお勧めしません。
★★★★★
各バイナリをString化 コンパイルに時間が掛かりすぎました。無理です。手間はかかるようになりますが、どの道リバースエンジニアリングで流出してしまうので、この方法はダメです。 ★☆☆☆☆
各バイナリをString化+XorString(Xor暗号) 上述した通りコンパイルに凄く凄く時間が掛かりますが、XorString暗号化によりバイナリを強力に保護することができます。
もはやそこらのハッカーには手が出せないでしょう。
Xor暗号に関してはこちらで解説していらっしゃる方がおられましたので丸投げいたします。
★★★★☆
おまじない 手のひらと手のひらを合わせておまじないをしましょう。 ☆☆☆☆☆

ちなみにVMProtectにて難読化・仮想化とメモリやリソース等の各種保護をフルでおこなった状態がこちらです。
image.png
正直、これを突破するのは相当至難の業です。
専門家でもってしても一握りのみが手を出せる代物となってしまいました。
hacker_cracker3_cry.png何だよコレ!.NETじゃねーのかよ!やってれんわ!

最後に

以上「僕が考えた最強の.NETアプリケーションの(リバースエンジニアリングからの)保護」でした。
正直、難読化レベル云々よりこういった根本的なところから保護をすることが一番強力だということですね。

最後までご覧いただき、ありがとうございました。

記事内の情報に誤りがございましたら、コメント欄にてお気軽にご指摘いただけますと幸いでございます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VSCodeで.NET Frameworkコンソールアプリをビルド&デバッグする

Visual Studio Codeで、.NET Coreのビルド&デバッグはできるっぽいのですが、.NET Frameworkの方法が見つからなかったのでまとめてみました。

参考にしたのは、ここです。
Visual Studio Code for .Net Framework - Stack Overflow

Explorerから*.slnプロジェクトファイルのあるフォルダーを選択

プロジェクトファイルのあるフォルダーを開く

左上のアイコン「Explorer」をクリックして、「Add Folder」を選択して、.NET Frameworkコンソールアプリケーションのプロジェクトファイル(*.slnなど)があるフォルダーを選択して「Add」しましょう。

まだ、C#プログラミングのプラグインをVSCodeに入れていないようなら、自動的に「OmniSharp」などのプラグインが勝手にダウンロード&インストールされるかもしれませんが、その辺は今回、割愛。

ビルドタスク実行(とりあえずtasks.jsonの生成)

ショートカットキー「Ctrl+Shift+B」を押して、ビルドタスクの実行を行います。すると、まだビルド設定がないため、ウィンドウ上部に「tasks.json」を新たに作るようにメニューが現れます。
新しいtasks.jsonファイルを作る

新しい「tasks.json」を作ることを選択すると、下の画像のように何種類かのビルド設定が表示されますので、
MSBuildを選択する

「MSBuild」を選択しましょう。
デフォルトのtasks.jsonが作成される

すると、デフォルトの「tasks.json」ファイルが、*.slnなどのプロジェクトファイルのあるフォルダーに、「.vscode」というフォルダーを作成し、その中に「tasks.json」ファイルが作成されます。
tasks.jsonファイルは.vscodeフォルダーに作成される
tasks.jsonファイルが作成される

デフォルトでは、以下の内容の「tasks.json」ファイルが生成されます。

tasks.json
{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "build",
      "type": "shell",
      "command": "msbuild",
      "args": [
        // Ask msbuild to generate full paths for file names.
        "/property:GenerateFullPaths=true",
        "/t:build",
        // Do not generate summary otherwise it leads to duplicate errors in Problems panel
        "/consoleloggerparameters:NoSummary"
      ],
      "group": "build",
      "presentation": {
        // Reveal the output only if unrecognized errors occur.
        "reveal": "silent"
      },
      // Use the standard MS compiler pattern to detect errors, warnings and infos
      "problemMatcher": "$msCompile"
    }
  ]
}

tasks.jsonの書き換え

もちろん、このままでは使えないので全面的に書き換えます。

なお、tasks.jsonの設定については、以下のページが参考になります。
https://code.visualstudio.com/docs/editor/tasks

tasks.json
{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      //【重要】タスク名を記載する(後述のlaunch.jsonと連動します)
      "label": "debug msbuild",
      // プログラムの種類
      "type": "shell",
      // ビルドツール(MSBuild.exe)の位置。以下の例ではv.4.0を使うのでその実行ファイルパスを指定します。
      "command": "C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe",
      // MSBuild.exeへの引数を指定します。
      "args": [ 
        // プロジェクトファイル(*.slnなど)のあるパスを指定します。
        "C:\\Users\\hibara\\Desktop\\ConsoleApp1\\ConsoleApp1.sln",
        // ターゲット(/target)をビルドする
        "/t:build",
        // プロジェクトのビルドに使用するツールセットのバージョン
        "/p:toolsVersion=4.0",
        // デバッグビルド
        "/p:Configuration=Debug",
        // プラットフォームは「Any CPU(32bit, 64bit)」
        "/p:Platform=\"Any CPU\""
      ],
      // タスクのグループを設定します。この場合は一つだけなので適当の「build」としました。
      "group": "build",
      // タスクの出力がユーザーインターフェースでどのように処理されるかを定義します。
      "presentation": {
        // 出力を表示する統合ターミナルが常に表示され、タスクの実行ごとに新しいターミナルが作成されます。
        "reveal": "always",
        // 実行後にターミナルウィンドウにフォーカスを移します(
        "focus": true,
      },
      // ビルドにエラーが発生した場合に、その出力から問題点を検出する際に使用する「プロブレムマッチャー」を指定する。
      // ここではC#のコードなので、"$msCompile"が指定されています。
      "problemMatcher": "$msCompile"
    }
  ]
}

MSBuild.exeの引数については以下のURLを参考にしてください。
https://docs.microsoft.com/ja-jp/visualstudio/msbuild/msbuild-command-line-reference?view=vs-2019

実行・デバッグ設定(とりあえずlaunch.jsonの生成)

次に、「launch.json」を用意します。このファイルを作成するときは、VSCodeの左側にある「run」アイコンをクリックします。
runアイコンをクリックする

クリックすると、VSCodeウィンドウ上部に「Select environment(環境設定選択)」が出てきますが、.NET Frameworkの選択項目はありませんので、とりあえず「.NET Core」を選択します。
.NET Coreの環境設定を選択する

すると、自動的に以下のような「launch.json」ファイルが生成されます。中身は、.NET Coreのものなので、このままでは使えません。
launch.json」ファイルが作られる

「launch.json」ファイルは、先ほど作成した「tasks.json」と同じ場所に生成されます。プロジェクトファイルがあるフォルダー、「.vscode」フォルダーの中です。
「.vscode」フォルダの中に「launch.json」が生成される

launch.jsonの書き換え

「launch.json」ファイルの中身は、以下のように大きく書き換えます。

launch.json
{
  // Use IntelliSense to find out which attributes exist for C# debugging
  // Use hover for the description of the existing attributes
  // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
  "version": "0.2.0",
  "configurations": [
    {
      // デバッグ時のウィンドウから実行を選択する際のメニュー項目名になります。
      "name": ".NET Launch (console)",
      // プログラムの種類は「Desktop CLR debugger」を指定します。
      "type": "clr",
      // 起動設定のリクエストの種類です。ここでは単純に「launch」です。
      "request": "launch",
      // 起動前のタスクを指定します。「tasks.json」内「label」で指定した名前を記載します。
      "preLaunchTask": "debug msbuild",
      // 起動する(ビルドされた)実行ファイルパスを指定します。
      "program": "C:\\Users\\hibara\\Desktop\\ConsoleApp1\\ConsoleApp1\\bin\\Debug\\ConsoleApp1.exe",
      // 上記の実行ファイルに付加する引数を以下に記載します。
      "args": [],
      // 作業ファイルのあるディレクトリーパスを指定します。この例では実行ファイルのある場所です。
      "cwd": "C:\\Users\\hibara\\Desktop\\ConsoleApp1\\ConsoleApp1\\bin\\Debug\\",
      // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
      // 上記URLにあるとおり、コンソールは、VSCode内のコンソールに表示されるように指定します。
      "console": "internalConsole",
      // デバッグ中にデバッグコンソール表示をどうするかを指定します。ここではスタートと同時に表示としています。
      "internalConsoleOptions": "openOnSessionStart"
    },
  ]
}

特に「preLaunchTask」は重要です。先ほど「tasks.json」内で記載した「label」と、同じ値を記載する必要があります。この例ですと、「"debug msbuild"」が、それです。

なお、「launch.json」ファイルについての詳細は以下のURLを参照してください。
https://code.visualstudio.com/docs/editor/debugging

プログラムの実行、デバッグ

これで準備が整ったので、再びVSCodeの左側にある「run」アイコンをクリックして、ウィンドウ上部に出てくるメニューから「.NET launch(console) (ConsoleApp1)」を選択、三角のアイコンを押して実行します。
コンソールアプリを選択・実行

ビルドされた後に、実行された結果は以下にあるようにVSCodeのコンソールウィンドウに表示されます。
プログラム実行結果の表示

なお、プログラムの停止は、ツールバーにある四角アイコンの停止ボタンをクリックしてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【C#】Array.Sortに勝てた話

初めに

本記事では特にコードとかは記載されません。

目的

C#にはusing systemで追加されるクラスでArrayクラスがあります、このクラスの中にはSort関数がありかなりの処理速度でソートをかけてくれます。
この速度になんか勝ちたいなと思いまして色々試してみました。

試したこと

とりあえず自分の中でソートといえばバブルソートクイックソートの2種類が主流です。
とりあえず各ソートの処理速度を見てみましょう。
各ソートは1万回ずつ実行した時の数値となっています。

バブルソート

a59c245735815260207550317024280e.png
こんな感じの速度ですね。

クイックソート

c92314c24c00d07349481f08ae57325a.png
やっぱりソート最速と噂されるソートなだけあって早いです。

Array.Sort

eb6f944a19fd535acfc8469efc0ca7ba.png

まとめ

クイックソートすごいですね、爆速です。
機会がありましたらソースも公開したいと思います。

追記

数回のテストで勝ってる!と思ってましたがもう何度かテストした結果ほぼ同じ速度であることがわかりました。
悔しい!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む