Laden...

Das Programmier-Spiel: nette Übungsaufgaben für zwischendurch

Letzter Beitrag vor 3 Jahren 762 Posts 773.469 Views

Hallo MarsStein,

meinst Lösung:

return new MyClass().GetType().GetNestedTypes(BindingFlags.NonPublic).First();

Ich hoffe mal, dass ich die Aufgabenstellung richtig verstanden habe.

zero_x

Hallo zero_x,

Ich hoffe mal, dass ich die Aufgabenstellung richtig verstanden habe. Leider nicht. Die Vorgabe ist ja, daß das Objekt vom Typ MyClass+MyNested sein muss und mit ToString() den an die Create-Methode übergebenen String - im Beispiel "nichts ist unmöglich" - ausgibt.

Bei Dir ist das Objekt aber vom Typ System.RuntimeType und gibt mit ToString() "MyClass+MyNested" aus 😉

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

Dir gehts darum die Kapselung auszuhebeln also zugriff auf
'private string name' zu nehmen wenn ich dich richtig verstanden habe.
Gut das geht auch mit Reflection: zero_x ich lass dir mal noch einen Versuch *g

Hallo Sebastian.Lange,

nein, das hast du falsch verstanden.

Die Aufgabe ist es, ein Objekt der geschachtelten und privaten Klasse MyNested zu erzeugen.

Dabei soll der Name zwar als Parameter übergeben werden, aber der Zugriff auf die Name-Property bzw. das dahinterliegenden Feld wird von der privaten Klasse durchgeführt (im Konstruktor und im ToString). Das ist nicht die Aufgabe des Codes, den man schreiben soll, sondern der soll "nur" das Objekt erzeugen.

herbivore

aber der Zugriff auf die Name-Property bzw. das dahinterliegenden Feld wird von der privaten Klasse durchgeführt (im Konstruktor

Wie soll das gehen, wenn der constructor so aussieht:

    private MyNested() { }

Also sowohl constructor aufrufen, alsauch das feld name setzen^^

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Hallo,

Also sowohl constructor aufrufen, alsauch das feld name setzen^^

Das tifft den Nagel auf den Kopf 👍

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

Meine Lösung:


static object CreateForbiddenObject(string name)
        {                                    
            Type myType = new MyClass().GetType().GetNestedType("MyNested", BindingFlags.NonPublic);
            object myObject = Activator.CreateInstance(myType, true);
            
            FieldInfo fi = myType.GetField("name", BindingFlags.NonPublic | BindingFlags.Instance);
            fi.SetValue(myObject, name);
                        
            return myObject;

        }

Natürlich geht das ganze nur über Reflection:

Zuerst per Activator-Klasse eine Instanz von MyNested erstellen.
Dann kommt der eigentliche Gag: Per FieldInfo.SetValue bekommt man Zugriff auf das private Feld.

Zitat MSDN zu FieldInfo.SetValue

Hinweis

Voll vertrauenswürdiger Code verfügt über die Berechtigungen für den Zugriff auf private Konstruktoren, Methoden, Feldern und Eigenschaften mit Reflektion sowie für das Aufrufen dieser.

FieldInfo.SetValue-Methode (Object, Object)

using System;class H{static string z(char[]c){string r="";for(int x=0;x<(677%666);x++)r+=c[
x];return r;}static void Main(){int[]c={798,218,229,592,232,274,813,585,229,842,275};char[]
b=new char[11];for(int p=0;p<((59%12));p++)b[p]=(char)(c[p]%121);Console.WriteLine(z(b));}}

Hallo Scavanger,

Deine Lösung ist richtig, Du bist somit dran.

Meine eigene Lösung ist ähnlich, allerdings ohne FieldInfo zu benutzen, denn wenn man die Instanz hat kann kann man auch per Type.InvokeMember das private Feld setzen.
Btw.statt new MyClass().GetType() kann sich mit typeof(MyClass) das Erstellen einer Instanz von MyClass sparen.

Hier nochmal meine eigene Lösung:

  static object CreateForbiddenObject(string name)
  {
    Type t = typeof(MyClass).GetNestedType("MyNested", BindingFlags.NonPublic);
    object obj = Activator.CreateInstance(t, true);
    t.InvokeMember("name", BindingFlags.NonPublic|BindingFlags.SetField|BindingFlags.Instance,
                   null, obj, new object[] { name });
    return obj;
  }

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

ja das vorherige erzeugen war für mich so selbstverständlich das ich's garnicht erwähnt hab. war schon spät...
ansonsten wie schon gesagt das private feld noch mittels reflection setzen
(damit ToString() das richtige ausgibt)

Das Osterei für den Ex...

Hallo zusammen,

da der letzte Beitrag ja schon eine kleine Ewigkeit her ist, erlaube ich mir mal ein neues kleines Rätsel zu stellen. Ich formuliere die Frage mal so, wie sie bei einer Zertifizierungsprüfung gestellt würde. 😉

Sie arbeiten als Software-Enwickler bei der Firma Kleine Klitsche GBR und verwenden Visual Studio 2010 mit .NET 4 als Entwicklungsumgebung.

Trotz exzellenter Leistungen erhalten Sie die Kündigung. Sie haben durch Zufall erfahren, dass der Chef bei Kündigungen immer ein kleines Konsolenprogramm aufruft, um sämtliche Daten des Gekündigten aus dem System zu entfernen.

Bevor der Chef Sie jedoch aus dem Büro geleitet, bekommt er einen Anruf und lässt Sie für ein paar Minuten an Ihrem Platz allein. Schnell starten Sie Visual Studio und laden die Solution der kleinen Applikation. Damit ihre Änderung so unauffällig wie möglich bleibt, fügen Sie der Originaldatei nur ein einziges Wort hinzu. Allerdings verstecken Sie eine weitere Datei in den Tiefen der kleinen Applikation.

Gerade als Sie Ihre "Arbeit" abgeschlossen haben erscheint Ihr Gerade-Noch-Chef und geleitet Sie aus dem Büro. Kaum das er Sie vor die Tür gesetzt hat verschwindet der Jetzt-Ex-Chef in seinem Kämmerlein. Sie spitzen die Ohren und richtig: Keine zwei Minuten später hören Sie ein ersticktes Schluchzen aus eben diesem Kämmerlein und machen sich fröhlich pfeifend auf den Weg zum Arbeitsamt...

Was war geschehen? Jedes mal wenn der Zum-Glück-Nicht-Mehr-Chef der kleinen Applikation Ihren Namen übergibt erscheint derselbe Text auf dem Bildschirm:

[TT]c:\>KollegenKicker.exe "Ihr Name"
Bitte geben Sie den Namen des Angestellten an, den Sie feuern möchten!
c:\>
[/TT]

So sah das Programm vor Ihrer Änderung aus:

static class Program {

    [STAThread]
    static void Main(string[] args) {

        if (args.Length == 0 || args[0] == string.Empty) {
            Console.WriteLine("Bitte geben Sie den Namen des Angestellten an, den Sie feuern möchten!");
            return; 
        }

        // Jede 
        // Menge
        // Code
        // um
        // den
        // Angestellten
        // loszuwerden
        // ...

    }

}

Welches Wort fügen Sie in die Datei Program.cs ein, und welche Datei erstellen Sie noch um den gewünschten Effekt zu erreichen?

Es gewinnt die Antwort, die mit dem wenigsten Code auskommt!

Ich behaupte mal, dass es auch ohne ein Wort in Program.cs zu ändern geht, wenn man was in den Projekteigenschaften umstellt.

Btw: Gilt

+"Floste"

als ein Wort?

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Wie Floste vorgeschlagen hat einfach den Namen mit + an das string.Empty anfügen.
Alternativ:

if (args.Length() == 0 || args[0] == string.Empty) {
    Console.WriteLine("Bitte geben Sie den Namen des Angestellten an, den Sie feuern möchten!");
    return;
}
public static class X
{
    public static int Length(this string[] s)
    {
        return s.Length == 0 || s[0].Equals("MyUsername") ? 0 : 1;
    }
}

Alternativ: 😁

Exakt das gleiche hatte ich auch probiert, aber die property vom string hat vorrang -> geht nicht!

Vielleicht solltest du deinen code mal compilieren^^

Also ich finde es viel schöner einfach garnichts zu ändern an program.cs und stattdessen eine alternative main einzustellen:

using System.Linq;
using System.Reflection;

public static class ABoringClass
{
    static void Main(string[] args)
    {
        if (args.FirstOrDefault() == "Ihr Name") args[0] = "";
        typeof(Program).InvokeMember("Main", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Static, null, null, new object[1] { args });
    }
}

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

hmm, vielleicht solltest Du denn obigen Code mal kompilieren... ^^

oder doch mit ner extension. und dann aber ganz dreißt einen Buchstabendreher reinbauen. aus Length wird Lentgh 😉 Und schon kann mans mit ner Extensionmethode machen

Fehlermeldung:
Fehler 1 Methodenname erwartet. C:********\test\Program.cs 8 13 test
t

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

oder doch mit ner extension. und dann aber ganz dreißt einen Buchstabendreher reinbauen. aus Length wird Lentgh 😉 Und schon kann mans mit ner Extensionmethode machen

hmm, die Extensionmethod die ich oben gepostet habe funktioniert doch, auch mit dem Methodennamen "Length".
zumindest kompiliert das bei mir...

Hi,

mein erster gescheiterter Ansatz war einfach eine neue Main-Methode zu definieren, (ohne parameter, aber mit int als return typ) in der Hoffnung dass der Compiler irgendeiner Reihenfolge beim Ermitteln der Main-Methoden hat. Dem ist aber nich so, wenn mehrere passen könnten, gibts einfach den Fehler, dass mehrere Einstiegspunkte definiert sind.

Aber der wirkliche Trick besteht im Wörtchen partial.

Also wird die gegebende Klasse einfach als partial markiert und in der Solution die nachfolgende Datei irgendwoe versteckt hinzugefügt:

using System;
using System.Linq;

static partial class Program 
{
  static Program() // Typinitialisier! Ha, ich werd vor der Main gerufen!
  {
    if("MyName".Equals(Environment.GetCommandLineArgs().Last()))
    {
      Main(new string[0]); // Main kann man sogar für den Hack wiederverwenden
      Environment.Exit(0); // uuunnd tschüss
    }	
  }
}

beste Grüße
zommi

Hallo zommi,

der Trick mit dem partial-keyword und dem Typinitialisierer war gefragt. Allerdings kommt mein Typinitialisierer mit einer einzigen Zeile Code aus - ohne sich dabei auf die Kommandozeilenparameter zu beziehen 😉
Ich werd nochmal ein Weilchen warten und ansonsten meinen Code posten...

@AndereAnsätze: Egal was dabei rauskommt: bis jetzt ist zommi der erste der sich tatsächlich an die Aufgabenstellung gehalten hat. (Eine versteckte Datei in der Solution)...

Viele Grüße,
Markus 😃

Oder so...


        static void Main(string[] args)
        {
            if (args.Length == 0 || args[0] == String.Empty)
            {
                Console.WriteLine("Bitte geben Sie den Namen des Angestellten an, den Sie feuern möchten!");
                return;
            }
        }


    class String
    {
        public static string Empty = "Mein Name";
    }

Haha man muss nichtmal etwas in der Datei ändern.
Projekteigenschaften -> Anwendung -> Startobjekt: Hier wählt man einfach eine andere Klasse mit Main-Methode und kann tun was man will. 😃

Hallo bSharp,

auch deine Lösung erzielt den gewünschten Effekt, aber hält sich nicht ganz an die Aufgabenstellung. Allerdings hat deine Lösung auch was - denn wer vermutet schon, dass sich hinter einem String nicht ein System.String verbirgt...

Dann stelle ich hier mal meine Lösung vor. Die Ursprungsklasse wird (wie von zommi bereits vorgeschlagen) um das keyword partial ergänzt.

static partial class Program {

    [STAThread]
    static void Main(string[] args) {

        if (args.Length == 0 || args[0] == string.Empty) {
            Console.WriteLine("Bitte geben Sie den Namen des Angestellten an, den Sie feuern möchten!");
            return;
        }

        // Jede
        // Menge
        // Code
        // um
        // den
        // Angestellten
        // loszuwerden
        // ...

    }

}

Die andere Hälfte der Klasse Program, die wir dem Programm unterschieben enthält (wie von zommi vorgeschlagen) einen Typinitialisierer - denn nur der wird in diesem Beispiel vor der Methode Main ausgeführt.

Aber worin liegt nun die Magie die die Überprüfung in der originalen Main-Methode ein unerwartetes Ergebnis liefern lässt? Der gewünschte Effekt lässt sich mit einer einzigen Zeile voll Schabernack erzielen:

static partial class Program {

    static Program()  {
        typeof(string).GetField("Empty").SetValue(null, "Ihr Name");
    }

}

Da zommi an der Aufgabenstellung am nächsten dran war darf er weitermachen! 😃

Ich muss allerdings gestehen, dass ich nicht von ganz allein auf diese Aufgabenstellung gekommen bin: The Daily WTF: The Disgruntled Bomb (in den Kommentaren findet sich die Anregung...)

Viele Grüße,
Markus 😃

Hi Spontifixus,

danke für den Lösungs-Zuspruch und insbesondere Danke für die schöne Aufgabe. Ich kann nun hoffentlich etwas ähnlich schönes bieten:

Im Anhang befindet sich eine kleine .NET-Applikation die einen geheimen Text enthält. Dieser Text ist "verschlüsselt" hinterlegt und wird angezeigt, wenn man das richtige Password eingegeben hast.

[B]Wie lautet der geheime Text?[/B]
Alle Mittel und Wege sind zugelassen - seid kreativ !

 [color]Ich habe ein paar Abwehrmaßnahmen/Hindernisse/Fallstricke eingebaut, sonst macht es ja keinen Spaß ;)[/COLOR] Der verschlüsselte, geheime Text befindet sich in der statischen Variable CryptoGame.Program.CryptedText.

Möge der schnellste gewinnen! 😃

Viel Vergnügen und beste Grüße
zommi

morgen

besteht die möglichkeit das programm für eine frühere frameworkversion zu kompilieren?

MfG Paul

Lösung:

Der geheime Text lautet "Bankgeheimnis".
Das Passwort ist "lkgnjokfejjop";

Vorgehensweise:
Reflektor!

Code:


namespace PW_hack
{
    static class Program
    {
        private static int numberA;
        private static int numberB;
        private static int numberC;
        private static int baseCharacter = 0x6d;
        private static string CryptedText = "Cctjjcjlqpqgp";

        /// <summary>
        /// Der Haupteinstiegspunkt für die Anwendung.
        /// </summary>
        [STAThread]
        static void Main()
        {
            string refPass = Program.ReferencePassword();
            string refPassDecry = Program.Decrypt(refPass);

            string hashRef = Program.HashPassword(refPass);
            string hashEntered = Program.HashPassword("lkgnjokfejjop");

            bool result = hashRef == hashEntered; //Strike?
        }

        private static string ReferencePassword()
        {
            //Stupid Check removed...

            int[] numArray = new int[] { 11, 0x17, 0x3e, -11, 0x1f, -22, 0x18, 0x48, 0x53, 0x1f, 0x20, -24, -33 };
            numberA = 3;
            numberB = 7;
            numberC = -10; // hier auf -10 gesetzt, wie im Dissasebler gesehen (numberA + numberB = -10)

            StringBuilder builder = new StringBuilder();
            for(int i = 0; i < numArray.Length; i++)
            {
                char ch = (char)(baseCharacter + (numArray[i] / numberC));
                builder.Append(ch);
            }
            return builder.ToString();
        }

        private static string Decrypt(string password)
        {
            StringBuilder builder = new StringBuilder();
            for(int i = 0; i < Math.Min(password.Length, CryptedText.Length); i++)
            {
                builder.Append((char)((CryptedText[i] + password[i]) - baseCharacter));
            }
            return builder.ToString();
        }

        private static string HashPassword(string password)
        {
            byte[] bytes = Encoding.ASCII.GetBytes(password);
            return BitConverter.ToString(new MD5CryptoServiceProvider().ComputeHash(bytes));
        }
    }
}

Comment:
Das war ne sehr schöne Aufgabe, hat mir wirklich Spaß gemacht und meinem Chef 1h meiner Arbeitszeit gekostet.

Ich überleg mir was neues (Das ich das noch erlebe...).

Also wie du das mit den -10 rausgefunden hast bleibt mir ein Rätsel.

Ansonsten mit numA+numB kommt 10 raus(wie Reflector das halt auch anzeigt) und dann wäre das Passwort "noslpkotuppkj" und der geheime Text dann "Dezimalsystem";

Lg XXX

//EDIT: Lol aber mit der originalen Assembly funktionierts natürlich nicht. 😃

Also wie du das mit den -10 rausgefunden hast bleibt mir ein Rätsel.

Hi,

sehr gut! Dann bist du jetzt dran.

//EDIT: Lol aber mit der originalen Assembly funktionierts natürlich nicht. 😃 So war es gedacht 😉
Die normale Assembly über Reflection einfach ansprechen geht nicht so einfach, weil hash-checks auf die entry-assembly drin sind. Den Code aber einfach rauskopieren, kopiert etwas falsches, wegen dem "numberA + numberB" - Hack 😉
Wenn man übrigens genau hinschaut, sieht man dass der Reflector das "+" dazwischen auch grün macht, es also zum Bezeichner gehört anstatt schwarz wie den normalen Additionsoperator ;D

Und ich hab ganz schön lange gebraucht, bis ich ein Programm hab, was mir Wort-Paare ausspuckt, sodass bei dem +- Fehler beides mal sinnvolle Wörter rauskommen - damit man denkt, man sei bereits fertig 😉

Noch eine Frage an Joetempes. Konntest du den Program-Konstruktor mit dem Reflector ansehen? Den hab ich nämlich so manipuliert, dass Reflector bei mir in jeder Ansicht abschmiert 😉

beste Grüße
zommi

Hallo zommi,

der Konstruktor an sich ging nicht zu öffnen, es folgte eine Exception vom Reflactor.
Es ging nur so, wie in meinem angehängten Bild.

Also, ich überleg mir was...

Auch wenns schon gelöst ist:
Hier noch der Beweis das man den Konstruktor durchaus mit dem Reflektor ansehen kann: 😁

Vorgehensweise:
Die Assembly mit ildasm disassemblieren, die .il Datei öffnen, dann im Konstruktor den ganzen überflüssigen IL-Code rausschmeißen (was meinen Texteditor an den Rand der Leistungsfähigkeit brachte, so viele NOP auf einem Haufen! 8o). Dann sieht man eh schon was der Konstruktor eigentlich macht.
Jetzt noch mit ilasm neu kompilierten und: Tada!

Wenn man jetzt noch in der ReferencePassword()bei Instruktion 0018 aus "bne.un.s IL_0022" z.B.
"beq.s IL_002d" macht, umgeht man den Hash-Check und die neu kompilierte Assembly läuft.

using System;class H{static string z(char[]c){string r="";for(int x=0;x<(677%666);x++)r+=c[
x];return r;}static void Main(){int[]c={798,218,229,592,232,274,813,585,229,842,275};char[]
b=new char[11];for(int p=0;p<((59%12));p++)b[p]=(char)(c[p]%121);Console.WriteLine(z(b));}}

Mein Jade.NET kann das auch so, der generierte code ist aber etwas seltsam^^ Guter test iwie

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Ich gebe die Aufgabe ab, 24h sind mir zu kurz....

Ich gebe die Aufgabe ab, 24h sind mir zu kurz....

Das heißt dann wohl, ich darf eine stellen, wenn ich möchte?

Ich hab mal ein .net-programm geschrieben, das macht ne passwortabfrage. Es ist auf den ersten blick mit 65 zeilen ziemlich einfach und überschaubar, aber... guckt einfach selbst rein... 😁 :evil:

Ich habe auf ziemlich viele gemeinheiten verzichtet und es kommen keine hashes/kryptozeugs vor, kein dateizugriff und kein netzwerkzugriff, es wird kein code nachgeladen, es ist alles managed code und lässt sich mit reflector anzeigen.

Bin mal gespannt, wer als erster ne idee hat (oder auch nicht).
(Wenn jemand zweifeln sollte: es ist lösbar!)

Genaue aufgabenstellung: Finde eine eingabe, die das angehängte programm dazu bringt, "korrekt" auszugeben.

(Irgendwie denke ich, dass es niemand schaffen wird.)

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Ist cool, ist es überhaupt möglich ohne Eingriff ein "korrekt" zu erhalten?

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

Ich hab mir schon gedacht, dass das bezweifelt werden wird:

(Wenn jemand zweifeln sollte: es ist lösbar!)

JA, es ist möglich! Das ist ja grade das witzige^^

EDIT: Hab mir das ganze im reflector angeguckt. Das return false ist ziemlich falsch übersetzt! Es steht so nicht im code:


        return ergebnis;

Ich bleibe dabei: Es gibt eine lösung!

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

(Aufgrund des return false; auch meine Frage. =) Jade machts hingegen richtig.){gray}

Irgendwie hab ich das Gefühl ich überseh was...

Denn laut Code müssten eigentlich alle Einträge des Arrays (je Methode) passen. Also überseh ich definitiv den springenden Punkt warum sie es nicht tun.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

Denn laut Code müssten eigentlich alle Einträge des Arrays (je Methode) passen.

Jap, das ist 100% richtig!
Nur habe ich 2 msil-instruktionen vertauscht

Also überseh ich definitiv den springenden Punkt warum sie es nicht tun.

Der springende punkt ist ein typensprung.

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Sag mal zeigt dein Jade den Code in der richtigen Reihenfolge an? - Denn anders als beim Reflector seh ich darin die Prüfung der Eingabe vor der eigentlichen Eingabe.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

Eigendlich sollte es in der richtigen reihenfolge anzeigen, tut es allerdings in desem falle nicht 😦. es fehlt ein goto, das aus bestimmten gründen nicht angezeigt wird. Ich werd mich zur nächsten version ans beheben machen. Wenigstens kann ich mich trösten, dass reflector auch mist baut.

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Halloo Hacker-Community,

ich habs: das "Passwort" ist einfach System.String[]
Wie ich drauf gekommen bin? Ich weiß es grad selber nicht, ich weiß nur: geraten ist es nicht!

mfg.
markus111

[Follow me on Twitter](http://twitter.com/blendingsky)

AHHHHH!!!!!!!!!!

Verdammt! Manchmal sieht man den Wald ver lauter Bäumen nicht!
Ich war so kurz davor und eigentlich hatte ich es schon ich schon jetzt ist es klar!!!

Kopf -> Tisch!

X(

Aber dafür kann ichs erklären (glaube ich 😄)

Wenn man sich den IL-Code der Methoden TestE() und TestD ansieht fällt auf das die delegaten vertauscht werden.

Oben steht bei TestD :

locals init (class Program/'<>c__DisplayClass1' V_0,

aber weiter unten wird auf einmal ein Pointer auf die andere Methode erzeugt:

IL_00a0:  ldftn      instance void Program/'<>c__DisplayClass4'::'<TestD>b__3'(int32)

DisplayClass4 statt DisplayClass1!

In der anderen Klasse ist es umgekehrt, das sind die IL Instruktionen von denen Floste gesprochen hat.

So der zweite Teil liegt an der String.Concat (der Reflector verschluckt das, Jade zeigt es richtig an, der Reflector zeigt nur zwei verräterische Klammern an)

Wenn jetzt die "falsche" Methode aufgerufen wird ist wird die variable pws abgerufen ohne das sie initalisiert wurde übrig bleibt der Typ, der ist eben System.String[] der wird magischerweise fund zugewiesen, die eigentlich System-String ist (Aber warum? Das habe ich nicht ganz kapiert) und diese Variable wiederum wird dann an String.Concat(object) übergeben, diese Überladung ruft object.ToString() auf der den Typ als String zurückgibt, und das ist das richtige Passwort.

Ich hoffe das stimmt so.

using System;class H{static string z(char[]c){string r="";for(int x=0;x<(677%666);x++)r+=c[
x];return r;}static void Main(){int[]c={798,218,229,592,232,274,813,585,229,842,275};char[]
b=new char[11];for(int p=0;p<((59%12));p++)b[p]=(char)(c[p]%121);Console.WriteLine(z(b));}}

DisplayClass4 statt DisplayClass1!

In der anderen Klasse ist es umgekehrt, das sind die IL Instruktionen von denen Floste gesprochen hat.

Richtig 😁 👍

Wenn jetzt die "falsche" Methode aufgerufen wird ist wird die variable pws abgerufen ohne das sie initalisiert wurde übrig bleibt der Typ, der ist eben System.String[] der wird magischerweise fund zugewiesen, die eigentlich System-String ist (Aber warum? Das habe ich nicht ganz kapiert)

Mit magie hat das ganze nichts zutun.
Hehe, also übrigbleiben tut bei einer nicht initialisierten variable erstmal ein null.
Eigendlich wurde es ja initialisiert, nur sind im speicher die felder einer klasse keineswegs alphabetisch sortiert, sondern (mit bestimmten ausnahmen) in der reihenfolge, in der sie definiert wurden. Und in DisplayClass1 und DisplayClass4 sind die felder fund und pws im speicher vertauscht. Daher ist pws in fund zu finden und umgekehrt, wenn man einen reinterpret cast durchführt.
Da ein string[] aber dadurch immernoch kein string ist, ist ToString nötig, sonst gibts abstürtze, und um das unauffällig zu machen eben das Concat.

Markus war zwar schneller, aber irgendwie gefällt mir deine Antwort besser, Scavanger.
Gelöst ist es in jedem Fall. -> Der Nächste kann ne Aufgabe stellen

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Wäre es noch möglich, dass du deinen Code uploadest?

@Daniel B.:

Welchen Code? Lade dir die Assemly und schau sie dir in Jade.net/Reflector oder jage die Assembly durch Ildasm, so wie es gedacht ist... 😉

O.K.,
dann doch mal eine neue Aufgabe:

Das Ziel besteht darin ein kleines Programm zu schreiben das folgenden Kartentrick vorführt:

Sie suchen sich aus 20 verschiedenen Spielkarten (z.B. 10 - Ass, alle Farben) eine Karte aus und merken sie sich. Ich lege die Karten sichtbar nacheinander auf 5 Stapel (nach dem letzten Stapel beginne ich wieder mit dem ersten) und sie sagen mir in welchen Stapel sich die Karte befindet. Das ganze wird nochmal wiederholt allerdings nur mit 4 Stapeln.
Danach sage ich ihnen welche Karte sie sich ausgesucht haben.
Edit:
Wegen einer Nachfrage:
Die Stapel werden zwischen den beiden Durchgängen nicht gemischt, d.h. die Reihenfolge der Karten bleibt immer gleich.

Eine Konsolenanwendung reicht völlig aus, auf den Lösungsalgorithmus kommts an 😉

Viel Spass!

using System;class H{static string z(char[]c){string r="";for(int x=0;x<(677%666);x++)r+=c[
x];return r;}static void Main(){int[]c={798,218,229,592,232,274,813,585,229,842,275};char[]
b=new char[11];for(int p=0;p<((59%12));p++)b[p]=(char)(c[p]%121);Console.WriteLine(z(b));}}

Das Beispiel sollte gelöst sein - Neue Angabe kommt bald 😃

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace kartentrick
{
    class Program
    {
        static char[] colors = { 'H', 'K', 'P', 'Z' };
        static string[] cardtypes = { "Zehn", "Bube", "Dame", "König", "Ass" };

        static void Main(string[] args)
        {
            Console.WindowWidth = 90;
            string[] cards = GetCardPack();
            Print(5, cards);
            Console.Write("\nIn welchem Stapel ist ihre Karte?: ");
            string input = Console.ReadLine();
            Print(4, cards);
            Console.Write("\nIn welchem Stapel ist ihre Karte?: ");
            string stacknum = Console.ReadLine();
            string choosen = RetrieveChoosenCard(int.Parse(input), int.Parse(stacknum), cards);
            Console.Clear();
            Console.WriteLine("Ihre Karte: {0}", choosen);
            Console.ReadLine();
        }

        /// <summary>
        /// Gibt die gesuchte Karte zurück
        /// </summary>
        static string RetrieveChoosenCard(int fiveStack, int fourStack, string[] cards)
        {
            for (int i = 0; i < 4; i++)
            {        
                for (int j = 0; j < 5; j++)
                {
                    if (cards[i * 5 + fiveStack-1] == cards[j * 4 + fourStack - 1])
                    {
                        return cards[i * 5 + fiveStack - 1];
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// Initialisiert Karten und mischt sie
        /// </summary>
        /// <returns></returns>
        static string[] GetCardPack()
        {
            string[] pack = new string[20];
            int ct = 0;
            for (int i = 0; i < cardtypes.Length; i++)
            {
                for (int j = 0; j < colors.Length; j++)
                {
                    pack[ct] = colors[j] + " " + cardtypes[i] ;
                    ct++;
                }
            }
            Random random = new Random();
            for (int i = 0; i < 50; i++) //Funktion zum Mischen der Karten
            {
                int a = random.Next(0, 20);
                int b = random.Next(0, 20);
                if (a != b)
                {
                    string swap = pack[a];
                    pack[a] = pack[b];
                    pack[b] = swap;
                }
            }
            return pack;
        }

        static void Print(int stackcount, string[] cards)
        {
            for (int i = 0; i < stackcount; i++)
            {
                Console.Write("{0}.Stapel\t", i + 1);
            }
            Console.WriteLine("\n");
            int ct = 0;
            for (int i = 0; i < 20 / stackcount; i++)
            {
                for (int j = 0; j < stackcount; j++)
                {
                    Console.Write(cards[ct] + "\t\t");
                    ct++;
                }
                Console.WriteLine();
            }
        }
    }
}
Hinweis von talla vor 13 Jahren

Das Beispiel sollte gelöst sein

Ich möchte nochmal darauf hinweisen, dass eine Aufgabe nur dann gelöst ist, wenn der Aufgabensteller es bestätigt, nicht wenn der Lösende einfach sagt das sie gelöst sein müsste! (Oder aber natürlich aufgrund von lang andauernder Inaktivität keine Antwort mehr zu erwarten ist)

ja natürlich - ich hatte auch nicht vor eine Angabe zu Posten bevor eine Bestätigung erfolgt 😉

Interessante Lösung,so gehts natürlich auch, aber eigentlich wollte ich auf eine andere
Lösung hinaus:

Den chinesisches Restsatz:

Den ganzen "Trick" kann man als ein System von Kongruenzen betrachten.
Die Nummer des Stapels entspricht der Restklasse der gemerkten Kartennummer im Stapel Modulo 5 bzw. 4. Da 5 und 4 paarweise Teilerfremd sind gibt es eine eindeutige Lösung in der Menge { 1 ... 20 } (Z 20) (5x4 = 20).

Nun benötigt man die modular Inversen von 20 bzgl. mod 5 und 4:

M1 = 20 / 5 = 4 ~M1 = 4 mod 5 = 5 N1 = 4 * 4 = 16

M2 = 20 / 4 = 5 ~M2 = 5 mod 4 = 1 N2 = 1 * 5 = 5

Um nun die gemerkte Karte zu berechnen braucht man nur noch einsetzen und ds ganze mod 20 zu nehmen:

Karte(nummer) = (stapelNr1 * 16 + stapelNr2 * 5) mod 20

Genauer ist der Chinesische Restatz hier. Chinesischer Restsatz erklärt

Und noch meine Variante:

using System;
using System.Collections.Generic;
using System.Text;

namespace Kartentrick
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WindowWidth = 120;
            
            Console.WriteLine("Bitte eine Karte aussuchen und merken:\n");
            
            string[] karten = InitKarten();
            AusgabeStapel(5, karten);
           
            Console.Write("\nIn welchem Stapel liegt ihre gemerkte Karte? ");
            
            int stapel1;
            while (!int.TryParse(Console.ReadKey(false).KeyChar.ToString(), out stapel1) || (stapel1 < 1 || stapel1 > 5 ))
                Console.Write("\nUngültige Eingabe. In welchem Stapel liegt ihre gemerkte Karte? ");
            
            Console.Write("\n\n");
            AusgabeStapel(4, karten);
            Console.Write("\nIn welchem Stapel liegt ihre gemerkte Karte jetzt? ");
            
            int stapel2;
            while (!int.TryParse(Console.ReadKey(false).KeyChar.ToString(), out stapel2) || (stapel2 < 1 || stapel2 > 4))
                Console.Write("\nUngültige Eingabe. In welchem Stapel liegt ihre gemerkte Karte? ");
            
            Console.WriteLine("\n\nIhre gemerkte Karte: " + karten[GetKarte(stapel1, stapel2) -1 ]);
            Console.ReadKey();
        }
                
        static int GetKarte(int stapel1, int stapel2)
        {
            // Chinesischer Restsatz, siehe Posting  
            return (stapel1 * 16 + stapel2 * 5) % 20;  
        }

        static string[] InitKarten()
        {
            string[] farben = { "Kreuz", "Karo", "Herz", "Pik" };
            string[] werte = { "Zehn", "Bube", "Dame", "König", "Ass" };

            string[] karten = new string[20];

            for (int i = 0; i < 20; i++)
                karten[i] = farben[i % 4] + " " + werte[i % 5];

            Shuffle<string>(karten);

            return karten;
        }

        static void AusgabeStapel(int anzStapel, string[] karten)
        {
            for (int i = 1; i <= anzStapel; i++)
                Console.Write("{0,-15}", i);
            
            Console.Write('\n');
            for (int i = 1; i <= 20; i++)
            {
                Console.Write("{0,-15}", karten[i-1]);
                if (i % anzStapel == 0)
                    Console.Write('\n');
            }
        }

        private static Random rand = new Random();
        public static void Shuffle<T>(IList<T> ilist)
        {
            int iIndex;
            T tTmp;
            for (int i = 1; i < ilist.Count; ++i)
            {
                iIndex = rand.Next(i + 1);
                tTmp = ilist[i];
                ilist[i] = ilist[iIndex];
                ilist[iIndex] = tTmp;
            }
        }
    }
}


@Daniel B:

Du bist dran

using System;class H{static string z(char[]c){string r="";for(int x=0;x<(677%666);x++)r+=c[
x];return r;}static void Main(){int[]c={798,218,229,592,232,274,813,585,229,842,275};char[]
b=new char[11];for(int p=0;p<((59%12));p++)b[p]=(char)(c[p]%121);Console.WriteLine(z(b));}}

Dankeschön und auf zur nächsten Aufgabe!

Für einen Leveleditor für das Spiel "Pacman" (Pacman) ist eine Überprüfung notwendig, ob Pacman auf ein beliebiges Feld zugriff hat.

Es ist eine Methode zu erstellen die mindestens diesen Kopf aufweisen muss:


private bool IsAccessable(int sourceX, int sourceY, int destX, int destY){ ... } 

Natürlich dürfen mehr Parameter verwendet werden bzw. x/y als Point realisiert werden.

Die Methode soll 'true' zurückgeben, wenn man vom Startpunkt den Zielpunkt erreichen kann, ansonsten 'false'. Das Feld in dem ihr euch befindet ist ein 2D-Buttonarray. Ein "befahrbares" Feld hat in den Himmelsrichtungen eine "Schranke" die geöffnet oder geschlossen werden kann.

Um mit meinem Leveleditor ein Level zu erzeugen müsst ihr einfach oben im Toolstripmenü auf 'new' klicken (Funktioniert nur einmal pro Start!). Man kann dann das Feld beliebig verändern und jederzeit über das ToolStripItem 'CanPacmanAccess?' testen, ob Pacman den Käfig der Geister erreichen kann!. Die öffentlichen Variablen könnt ihr unter der Region 'Variables' finden, der Rest des Projekts sollte nicht von Belang sein.

Um nicht zu vergessen: Das ToolstripItem 'CanPacmanAccess?' muss ebenfalls implementiert werden. Dort wird eure Methode aufgerufen (siehe Source im Anhang).

Ich habe noch zwei Bilder in den Ordner gepackt, was eventuelle Testfälle sein könnten.

Sollten noch unklarheiten bestehen habt keine Angst mich zu fragen 😉

Viel Spaß!

Hi,

ich habe mir gerade das Projekt angeschaut und wollte schon anfangen, jedoch habe ich jetzt nur noch Fragezeichen über meinem Kopf.

Dein Aufbau wie ich ihn verstanden habe:
Du hast gaaaanz viele Buttons, wobei es 4 Typen gibt. Die flächen (Pacmans gehweg) , die kleinen Ecken und Horizontale sovie Vertikale Schranken, wie du sie nennst. In den Schranken unterscheidest du anhand der Backgroundcolor ob sie offen oder zu ist.
Das ganze hast du in deinem Array pacmanField.

Was mir zum Lösen dieser Aufgabe ganz klar fehlt ist eine Funktion, mit der ich per X und Y Angabe an jede Fläche komme (Pacmans gehweg) und über diese Fläche an die Schranken dieser Fläche, wobei sich jedoch 2 Gehwege die Schranke dazwischen teilen.
Oder:
Eine Unterscheidung in den Buttons in pacmanField, weil sowohl schranken als auch Felder nur ihre Kordinaten im Tag-Feld haben.

Ich stoppe an dieser Stelle mit dem Forschen in deinem Quellcode und hoffe auf konkretere Vorstellungen für den Lösungsweg.

Gruß
Torley

Du kannst um nur die Felder durchzulaufen den Delegate ganz oben verwenden (ChangeButton) und dann rufst du einfach die Methode 'AccessAllField' auf (Beachte dass du bei dem referenzierten Button IMMER null kriegst!). Der Methode übergibst du einfach den Delegaten der benötigt wird und null falls du beispielsweise bei einer Ecke nichts unternehmen möchtest. Des Weiteren kann man ein Feld daran erkennen, dass beide Koordinaten ungerade sind.
Wenn du noch wissen willst was es ist (Feld, Schranke, Ecke,...) kannst du das vlt. im Control.Name Prop. abspeichern:


     private void InitEdge(ref Button b, int i, int h)
        {
           .
           .
           .
           .
            b.Name = "Ecke";
        }

        private void InitField(ref Button b, int i, int h)
        {
          
           .
           .
           .
           .
            b.Name = "Feld";
        }

        private void InitHorStone(ref Button b, int i, int h)
        {
           
           .
           .
           .
           .
            b.Name = "HSchranke";
        }

        private void InitVerStone(ref Button b, int i, int h)
        {
           .
           .
           .
           .
             b.Name = "VSchranke";
        }

//EDIT: Im angehängten Bild siehst du wie du die Schranken des Feldes kriegst