Was ist für Dich "Geschickt in C"? Auf portable oder schmutzige Art und Weise?
Wenn man es portabel macht, erübrigt sich zumindest die erste Frage.
for (uint8_t i = 0; i < 16; i++)
{
1
test ^= *(uint32_t*)(data); // ???
}
Deine Laufvariable wird im Array-Zugriff nicht mit einbezogen, Du greifst daher immer auf dieselben Daten zu. Außerdem ist Dein Zugriff eher "schmutzig" und nicht portabel. Denn er setzt voraus, dass die Endianess des Mikrocontrollers und der Daten identisch ist.
Geh nochmal zurück in Dein C-Buch. Dieser Code macht überhaupt nichts.
Eine gerade Anzahl von EXORs mit dem gleichen Wert läßt einen Wert unverändert.
Und ein Cast eines Pointers zu einen Typ mit anderer Bitbreite knallt ganz gewaltig. Ein Cast ist keine Konvertierung.
Für mich sieht das so aus, als ob eine Art Checksum über ein 16x uint_32 Feld gemacht werden soll. Und das könnte man tatsächlich unabhängig von der Byteorder machen, weil es keinen Übertrag in ein anderes Byte gibt. Allerdings müsste man dann den Pointer wenigstens mal hochzählen und auch value sinnvoll initialisieren.
Hallo,
es ist eigl. relative einfach wenn man sich einmal mit Bit-shiften beschäftigt hat.
Nimm dir ne größere variable(uint16_t , uint32_t , etc). Danach den 8 Bit Wert und schriebst den an die richtige Position und ODER_Verknüpft die beiden.
ODER --> Variable setzen
UND --> Variable löschen.
Und spätestend beim zweiten long geht es schief, denn der Wert 0x51 taucht bei dir irgendwie nicht auf...
Klar, denn das i*5 ist sicher falsch, denn eine ungerade Zahl ist keine Zweierpotenz. Und wir haben es hier ausschließlich mit Zweierpotenzen (konkret dem Faktor 4) zu tun.
Da man sowas ja öfters gebrauchen kann, könnte man für die Umwandlung von eine Funktion einführen.
1
for(inti=0;i<16;i++){
2
ui32_data[i]=convert(&data[4*i]);
3
}
Und datasollte nach Möglichkeit read-only sein, genauso wie ui32_data (was in C aber nicht wirklich machbar ist).
Problematisch ist auch die Abhängigkeit zwischen den Array-Größen.
Daher die Frage: ist wirklich C? Oder C++?
Warum wird hier keine Union vorgeschlagen?
union
{
uint8_t array[64];
uint32_t data[16];
}
Den array im Union mit den obigen Daten füllen und mit data[index] zugreifen.
Sollte so funktionieren.
Das ist einerseits UB, weil es die aliasing-Regeln verletzt, andererseits kann es zu Alignment-Problemen kommen, da data nicht unbedingt ein für uint32_t geeignetes Alignment hat.
So hätte ich es wahrscheinlich auch gelöst, dann weiß man auch in drei Monaten noch mal mit dem ersten Blick, was da genau wie gemacht wird bzw. gemacht werden soll. ;)
Für das reine XOR ist es egal, ob ich 32 Bit auf einmal verarbeite oder jedes Byte einzeln.
d.H.:
1
uint32_tchksum(uint8_t*data){
2
uint8_ttest[4]={0,0,0,0};
3
for(inti=0;i<64;i+=4){
4
test[0]^=data[i];
5
test[1]^=data[i+1];
6
test[2]^=data[i+2];
7
test[3]^=data[i+3];
8
}
9
// erst hier wird die gewünschte Byte-Order wichtig:
10
returntest[0]|test[1]<<8|test[2]<<16|test[3]<<24;
11
}
Bevor jemand meckert, dass das ineffektiv ist: Erstmal anschauen was der Compiler draus macht (-O3 unrollt die ganze Loop und macht am PC ein MMX-XOR daraus, lieber -Os testen), und überlegen wie ein 8-Bit-µC wohl ein 32-Bit XOR ausführt.
Und das mit der mag. Zahl 64 würde ich mir auch noch mal überlegen ;-)
Selbstverständlich. Hab ich nur schnell so hingeschrieben, weil der Compiler sonst die ganze Funktion (mit dem data-Array aus dem Original Post) zu einem "return Konstante" zusammengefasst hat.
Ja, wir sind ja schon im "von links nach rechts" Kulturkreis, aber trotzdem würde ich da für etwas Deobfuscation die bei Zahlen übliche absteigende Variante wählen:
1
returntest[3]<<24|test[2]<<16|test[1]<<8|test[0];
EDIT: und natürlich gehen hier alle 3 Shifts shief, weil wegen uint8_t immer 0 rauskommt.
Läd erst das ganze Input-Array in Register, und XORed das dann Baumartig zusammen, bis nur noch ein Register übrig ist, und XORed den Rest dann (einmal um 8 bytes, einmal um 4 Bytes verschoben) mit sich selber zusammen, und ist fertig.