7

C# に移植する必要がある C のコードがあります。

void CryptoBuffer(unsigned char *Buffer, unsigned short length)
{
    unsigned short i;
    for(i=0; i < length; i++)
    {
        *Buffer ^= 0xAA;
        *Buffer++ += 0xC9;
    }
}

私はこれを試しました:

public void CryptoBuffer(byte[] buffer, int length)
{
    for(int i = 0; i < length; i++)
    {
        buffer[i] ^= 0xAA;
        buffer[i] += 0xC9;
    }
}

しかし、結果は期待したものと一致しません。

例によると、これは次のとおりです。

A5 03 18 01...

これになるはずです:

A5 6F 93 8B...

また、最初のバイトは暗号化されていないため、A5 は同じままです。

明確化のための編集:仕様では、最初のバイトをスキップする必要があると書かれていますが、詳細には触れていないため、最初のバイトをスキップするには、位置1から最後の位置までシーケンスを渡すだけだと思います。

しかし、その C# ポートでの私の結果は次のとおりです。

A5 72 7B 74...

このポートは正しいですか、それとも何か不足していますか?

EDIT 2:さらに明確にするために、これはクローズドプロトコルであるため、詳細を説明することはできません。そのため、コードを移植するのに役立つ十分な情報を提供しました。仕様が何をすると言ったか。本当の問題は、仕様で「0xAA」が間違っていたことでした。そのため、出力が期待されたものではありませんでした。ここで提供され、受け入れられた回答によって提供されるC#コードは、結局のところ正しいです。

4

7 に答える 7

9

一度に一歩ずつ分解していきましょう。

void CryptoBuffer(unsigned char *Buffer, unsigned short length)
{
    unsigned short i;
    for(i=0; i < length; i++)
    {
        *Buffer ^= 0xAA;
        *Buffer++ += 0xC9;
    }
}

他のいくつかの意見に関係なく、これ通常C /C++でこれらのことを行う方法です。このコードには特別なことは何もありませんし、それほど複雑でもありませんが、何が起こるかを示すためにコードを分解するのは良いことだと思います。

注意事項:

  1. unsigned charは、基本的にc#のbyteと同じです。
  2. 符号なしの長さの値は0〜65536です。Intがそのトリックを実行する必要があります。
  3. バッファにはポストインクリメントがあります
  4. バイト割り当て(+ = 0xC9)はオーバーフローします。オーバーフローした場合、この場合は8ビットに切り捨てられます。
  5. バッファはptrによって渡されるため、呼び出し元のメソッドのポインタは同じままです。
  6. これは単なる基本的なCコードであり、C++ではありません。ここでは、演算子のオーバーロードを使用しないと想定するのは非常に安全です。

ここでの唯一の「難しい」ことはBuffer++です。詳細はSutterの「ExceptionalC++」という本で読むことができますが、小さな例でもこれを説明しています。そして幸いなことに、私たちは自由に使える完璧な例を持っています。上記のコードの直訳は次のとおりです。

void CryptoBuffer(unsigned char *Buffer, unsigned short length)
{
    unsigned short i;
    for(i=0; i < length; i++)
    {
        *Buffer ^= 0xAA;
        unsigned char *tmp = Buffer;
        *tmp += 0xC9;
        Buffer = tmp + 1;
    }
}

この場合、一時変数は簡単に解くことができ、次のようになります。

void CryptoBuffer(unsigned char *Buffer, unsigned short length)
{
    unsigned short i;
    for(i=0; i < length; i++)
    {
        *Buffer ^= 0xAA;
        *Buffer += 0xC9;
        ++Buffer;
    }
}

このコードをC#に変更するのはとても簡単です。

private void CryptoBuffer(byte[] Buffer, int length)
{
    for (int i=0; i<length; ++i) 
    {
        Buffer[i] = (byte)((Buffer[i] ^ 0xAA) + 0xC9);
    }
}

これは基本的に移植されたコードと同じです。これは、どこかで何か他の問題が発生したことを意味します...では、暗号バッファをハックしましょう。:-)

(あなたが述べたように)最初のバイトが使用されておらず、「0xAA」および/または「0xC9」が間違っていると仮定した場合、単純にすべての組み合わせを試すことができます。

static void Main(string[] args)
{
    byte[] orig = new byte[] { 0x03, 0x18, 0x01 };
    byte[] target = new byte[] { 0x6F, 0x93, 0x8b };

    for (int i = 0; i < 256; ++i)
    {
        for (int j = 0; j < 256; ++j)
        {
            bool okay = true;
            for (int k = 0; okay && k < 3; ++k)
            {
                byte tmp = (byte)((orig[k] ^ i) + j);
                if (tmp != target[k]) { okay = false; break; }
            }
            if (okay)
            {
                Console.WriteLine("Solution for i={0} and j={1}", i, j);
            }
        }
    }
    Console.ReadLine();
}

そこに行きます:おっと、解決策はありません。これは、暗号バッファが思ったとおりに動作していないか、Cコードの一部がここにないことを意味します。F.ex. 彼らは本当に'Buffer'をCryptoBufferメソッドに渡しますか、それとも以前にポインターを変更しましたか?

結論として、ここでの唯一の良い答えは、この質問を解決するための重要な情報が欠落しているということだと思います。

于 2013-03-08T21:36:39.810 に答える
5

提供された例は、C サンプルのコードと矛盾しており、C と C# のコードは同じ結果を生成します。

于 2013-03-04T22:36:26.880 に答える
3

移植は正しく見えます。03が6Fになる理由を説明していただけますか?結果が03までに「期待値」から外れているように見えるという事実は、私には少し疑わしいです。

于 2013-03-04T21:53:06.100 に答える
1

ポートは正しく見えます。

この状況で私がすることは、一枚の紙とペンを取り出し、バイトをバイナリで書き出し、XOR を実行してから加算することです。これを C および C# コードと比較します。

于 2013-03-04T21:50:01.293 に答える
1

C# では、バイトがオーバーフローしているため、0x72 に切り捨てられます。バイナリと 16 進数の両方で 0x03 を変換するための計算は次のとおりです。

   00000011   0x003
^  10101010   0x0AA
=  10101001   0x0A9
+  11001001   0x0C9
= 101110010   0x172
于 2013-03-04T21:52:40.733 に答える
0

ここにデモンストレーションがあります

http://codepad.org/UrX0okgu

を入力すると、元のコードが をA5 03 18 01生成することをD8 72 7B 01示します。それで

  1. 最初のバイトがデコードされないというルールは、バッファが 2 番目から送信される場合にのみ正しい可能性があります (コールを表示してください)。

  2. 出力が一致しません (他の呼び出しを見逃していませんか?)

あなたの翻訳は正しいですが、元のコードが何をするかについてのあなたの期待はそうではありません。

于 2013-03-14T14:44:21.333 に答える
0

C の元のメソッドでは、最初に、シーケンスが対称的な方法で復号化/暗号化されると仮定します。CryptoBuffer

  • 最初に呼び出すa5 03 18 01 ...

    a5 03 18 01 ... => d8 72 7b 74 ... 
    

    その後d8 72 7b 74 ...

    d8 72 7b 74 ... => 3b a1 9a a7 ...
    
  • 最初に呼び出すa5 6f 93 8b ...

    a5 6f 93 8b ... => d8 8e 02 ea ...
    

    その後d8 8e 02 ea ...

    d8 8e 02 ea ... => 3b ed 71 09 ... 
    

私たちはそれが実現不可能であることを知っています。

もちろん、非対称の復号方法を使用することもできます。しかし、最初に、a5 03 18 01 ... => a5 6f 93 8b ...可能性のある魔​​法の数で証明されているか、方向の逆が必要です。ブルート フォース アプローチによる分析のコードは、投稿の最後に配置されます。

テスト用にマジックナンバーを変数にしました。再現性分析により、連続的に変化するマジックナンバーで256回の呼び出しごとに元のシーケンスを再現できることがわかりました。わかりました、私たちが経験したことで、ここではまだ可能です.

ただし、両方の方向ですべてのケースをテストする実行可能性分析は、 fromとなしで成功します。256*256=65536original => expectedexpected => original

これで、暗号化されたシーケンスを期待どおりの結果に復号化する方法がないことがわかりました。

したがって、言語またはコードの両方の期待される動作は同一であるとしか言えませんが、仮定が壊れているため、期待される結果は不可能です。


分析用コード

public void CryptoBuffer(byte[] buffer, ushort magicShort) {
    var magicBytes=BitConverter.GetBytes(magicShort);
    var count=buffer.Length;

    for(var i=0; i<count; i++) {
        buffer[i]^=magicBytes[1];
        buffer[i]+=magicBytes[0];
    }
}

int Analyze(
    Action<byte[], ushort> subject,
    byte[] expected, byte[] original,
    ushort? magicShort=default(ushort?)
    ) {
    Func<byte[], String> LaHeX= // narrowing bytes to hex statement
        arg => arg.Select(x => String.Format("{0:x2}\x20", x)).Aggregate(String.Concat);

    var temporal=(byte[])original.Clone();
    var found=0;

    for(var i=ushort.MaxValue; i>=0; --i) {
        if(found>255) {
            Console.WriteLine(": might found more than the number of square root; ");
            Console.WriteLine(": analyze stopped ");
            Console.WriteLine();
            break;
        }

        subject(temporal, magicShort??i);

        if(expected.SequenceEqual(temporal)) {
            ++found;
            Console.WriteLine("i={0:x2}; temporal={1}", i, LaHeX(temporal));
        }

        if(expected!=original)
            temporal=(byte[])original.Clone();
    }

    return found;
}

void PerformTest() {
    var original=new byte[] { 0xa5, 0x03, 0x18, 0x01 };
    var expected=new byte[] { 0xa5, 0x6f, 0x93, 0x8b };

    Console.WriteLine("--- reproducibility analysis --- ");
    Console.WriteLine("found: {0}", Analyze(CryptoBuffer, original, original, 0xaac9));
    Console.WriteLine();

    Console.WriteLine("--- feasibility analysis --- ");
    Console.WriteLine("found: {0}", Analyze(CryptoBuffer, expected, original));
    Console.WriteLine();

    // swap original and expected
    var temporal=original;
    original=expected;
    expected=temporal;

    Console.WriteLine("--- reproducibility analysis --- ");
    Console.WriteLine("found: {0}", Analyze(CryptoBuffer, original, original, 0xaac9));
    Console.WriteLine();

    Console.WriteLine("--- feasibility analysis --- ");
    Console.WriteLine("found: {0}", Analyze(CryptoBuffer, expected, original));
    Console.WriteLine();
}
于 2013-03-08T11:54:01.837 に答える