6
votes

C ++ Passer des octets de char * à un BYTE *

Je voudrais savoir comment passer / COPIER une séquence d'octets représentée par un char * à un BYTE * en C ++ sous Windows.

Disons J'ai ce char * :

const char *ByteString = "\x3B\xC8\x74\x1B"  

Comment pourrais-je COPIER chaque octet de ce char * en un BYTE * Bytes et vice-versa?

EDIT: Merci beaucoup pour l'aide de tous!


12 commentaires

@ FrançoisAndrieux le BYTE défini par l'API Windows


Notez que demander une conversion de const char * en Byte * peut vous donner des réponses différentes de la conversion en const Byte * .


@CataCata Juste par curiosité: quelle fonction API appelez-vous?


@TedLyngmo J'utilise juste ReadProcessMemory et je compare des octets. Rien d'extraordinaire


@TedLyngmo J'ai un problème avec la réponse que vous avez fournie ... Disons que j'ai ce caractère * ByteString = "\ xA1 \ x00 \ x00 \ x00 \ x00 \ x3B \ xC8 \ x74 \ x1B". Lors de la vérification pour voir si la copie a réussi comme ceci: std :: cout << std :: hex << (uintptr_t) (BytesPattern [i]) << std :: dec << std :: endl; Après avoir lu le premier / x00, les octets suivants semblent être différents de mon caractère *


Il est déclaré comme dans votre exemple basic_string, donc au lieu de Bytes, il s'appelle BytesPattern. Après avoir copié les octets de mon char * vers mon BYTE *, je m'attends à ce qu'ils soient les mêmes, mais voici mon problème lorsque j'ai \ x00 dans mon char *. Lors de l'impression de mon BYTE, je m'attends à ce qu'il soit: A1 00 00 ... 3B et ainsi de suite, mais ce que j'obtiens est A1 00 et aléatoire après le premier octet 00.


Ahh ... si vous copiez des chaînes littérales, la copie s'arrête au premier \ 0 . La chaîne basic_string est construite de cette façon. Vous devez ajouter un argument de longueur au constructeur si la chaîne contient 0: s


@TedLyngmo Je ne comprends pas, qu'est-ce que \ 0 a à voir avec la copie des octets? Ils sont divisés comme si \ x00


Lorsque la chaîne d'octets est construite, la chaîne d'origine est fournie. Sans argument de longueur, il utilise strlen pour déterminer la longueur de la chaîne. Cette fonction s'arrête au premier 0 qu'elle trouve.


@TedLyngmo J'ai essayé de le faire de cette façon afin de spécifier la longueur, mais cela fait toujours la même chose. BYTE * Bytes = (BYTE *) calloc (BytesSize + 1, sizeof (BYTE)); memmove (Bytes, BytesString, BytesSize); Où BytesSize est le nombre d'octets dans mon char *, pas la longueur de la chaîne.


@TedLyngmo nvm c'était le problème .. J'utilisais strcpy à un moment donné et cela me dérangeait .. Merci beaucoup pour votre aide et votre patience


Aucun problème! J'ai ajouté un autre exemple au bas de ma réponse qui, à mon avis, correspond mieux à vos besoins.


4 Réponses :


2
votes

Pour respecter const, utilisez

len = LenOfChrStr;
BYTE *Bytes = new BYTE[len];
memcpy(Bytes, ByteStr, len);

et vice versa:

const char *ByteString = reinterpret_cast<const char *>(Bytes);

Si vous voulez faire une copie du buffer pour que vous pouvez le modifier, utilisez

const BYTE *Bytes = reinterpret_cast<const BYTE*>(ByteString);


4 commentaires

Ah, c'est vrai: il faut garder le const. J'allais juste par la question dans la ligne d'objet. (caractère * -> BYTE *)


La longueur sera-t-elle égale au nombre d'octets représentés à l'intérieur de mon caractère * ou du numéro de caractère?


La longueur est le nombre d'octets


Idem avec cette méthode, lors du test pour voir si la copie a réussi, les octets semblent ne pas correspondre à mon caractère initial *: std :: cout << std :: hex << (uintptr_t) (Bytes [0]) << std :: dec << std :: endl; EDIT: J'utilisais / au lieu de \ ..



6
votes

La définition de BYTE est:

typedef unsigned char BYTE;

qui n'est pas la même chose qu'un const char , vous devez donc le convertir, mais notez que supprimer const de quelque chose déclaré const pour commencer avec des résultats dans un comportement non défini et essayer de changer réellement les données présentent un risque encore plus grand.

BYTE * Bytes = reinterpret_cast (const_cast (ByteString));

Modifier : Je viens de remarquer que la conversion d'un const char * en BYTE * était hors de question, mais je vais le laisser ici pour le moment.


La copie des données (pas comme une chaîne terminée par un zéro) pourrait être effectuée comme suit:

using BYTEstr = std::basic_string<BYTE>; // just for convenience

BYTEstr Buffer(1024, 0); // 1024 BYTES initialized with 0
BYTEstr Pattern({ 0xA1, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xC8, 0x74, 0x1B });

ReadProcessMemory(hProcess, lpBaseAddress, Buffer.data(), Buffer.size(), &lpNumberOfBytesRead);

BYTEstr::size_type pos = Buffer.find(Pattern);

if (pos == BYTEstr::npos) {
    std::cout << "Pattern not found\n";
} else {
    std::cout << "Pattern found at position " << pos << "\n";
}

Ou mieux:

std::basic_string<BYTE> Bytes({ 0xA1, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xC8, 0x74, 0x1B });

Mais étant donné la nature de ce que vous faites, vous pourriez probablement ignorer ces conversions et utiliser un tableau du type correct pour commencer par:

BYTE Bytes[] = { 0xA1, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xC8, 0x74, 0x1B };

ou

const char ByteString[] = "\x3B\xC8\x74\x1B";
std::basic_string<BYTE> Bytes( reinterpret_cast<const BYTE*>(ByteString), sizeof(ByteString)-1 );

// use Bytes
// Bytes.data()  returns a BYTE*
// Bytes.size()  returns the length.

Ceux-ci n'auront pas besoin de conversions lorsque vous traitez avec les données brutes BYTE . Voici un exemple utilisant ReadProcessMemory et une basic_string pour un tampon et un motif.

const char ByteString[] = "\x3B\xC8\x74\x1B";
BYTE* Bytes = new BYTE[sizeof(ByteString)-1];
std::memcpy(Bytes, ByteString, sizeof(ByteString)-1);

// Use your Bytes

delete[] Bytes; // manual delete when you are done


21 commentaires

Techniquement, simplement const_casting quelque chose qui est const * est UB, sans changer la valeur const vers laquelle il pointe. C'est aussi UB, et toute autre solution proposée l'est également.


@ N00byEdge pouvez-vous sauvegarder cela avec une référence? Tbh je ne pense pas, car sinon const_cast serait plutôt inutile


Le cast copie-t-il les octets de mon char * dans mon BYTE *? Puisque c'est le but final. J'ai peut-être mal formulé ma question.


Ah ... non, la seule chose copiée est le pointeur vers le premier caractère de la chaîne.


Le fait de ne pas lancer le pointeur fait simplement semblant qu'il pointe maintenant vers des BYTE au lieu de char . Il n'en crée pas de nouveaux.


@ N00byEdge et comment s'y prendrait-on pour copier réellement les octets représentés sous forme de char * dans un BYTE *?


Appelez-moi fou, mais si vous pouviez envisager de faire une copie de la chaîne, vous pourriez parfaitement bien la copier dans un tampon de lecture-écriture.


J'ai fait une réponse distincte pour la possibilité de faire une copie de tous les caractères dans un tampon de lecture / écriture. @CataCata


@ N00byEdge Super, j'ai ajouté la création d'une version basic_string pour obtenir des méthodes de chaînes astucieuses.


@TedLyngmo Le seul problème avec cela est qu'il ne peut pas transférer la propriété à la fonction appelée au cas où elle en aurait besoin. Cela dépendrait de la fonction en question.


@TedLyngmo en essayant de tester si la copie a réussi comme ceci: std :: cout << std :: hex << (uintptr_t) (Bytes [0]) << std :: dec << std :: endl; Les octets semblent ne pas correspondre à mon caractère initial *


@CataCata en raison d'une erreur dans votre code (en utilisant / au lieu de \ )


@ N00byEdge Bien sûr, les chaînes transfèrent la propriété en utilisant la sémantique de déplacement, ce qui est une façon plus propre de le faire i.m.o.


@ N00byEdge GOOD CATCH wholy je suis aussi aveugle qu'une chauve-souris ... Merci beaucoup à tous pour l'aide! Cela a résolu mon problème!


@TedLyngmo Oui. Mais l'API prend un BYTE * , peut-être un propriétaire.


Ensuite, je proposerais d'utiliser ma deuxième solution et non celle de basic_string .


Les objets déclarés const ne doivent pas nécessairement exister en mémoire. Donc, même lire à partir d'eux via une référence non-const est un comportement indéfini.


Aucun argument. C'était une approche à moitié pragmatique en mon nom puisque c'est Windows et probablement VS, cela fonctionnera très probablement. Je viens de remarquer que N00byEdge a dit quelque chose de similaire ci-dessus, mais je n'ai pas remarqué. C'est bien sûr correct aussi.


@ N00byEdge et Galik - a mis à jour ma réponse pour mentionner l'UB en rejetant simplement le const.


@TedLyngmo pourquoi utiliser new BYTE [sizeof (ByteString) -1]; ? Ne devrais-je pas spécifier le nombre d'octets au lieu de la longueur de la chaîne? Par exemple, en utilisant cette chaîne "\ x3B \ xC8 \ x74 \ x1B", il y a 4 octets. Aussi, pourquoi le -1? Merci encore pour votre aide !


La seule raison est que lorsque vous utilisez un littéral de chaîne, c'est qu'il ajoute automatiquement un \ 0 à la fin, ce qui rend les données que vous souhaitez réellement utiliser un caractère supplémentaire. Si vous utilisez des chaînes C (qui sont terminées par \ 0 ), tout ira bien, mais traiter avec des motifs où les zéros sont une grande partie - non. sizeof sur un char [] vous donnera la taille exacte - y compris le \ 0 supplémentaire, dont vous n'avez pas besoin pour la correspondance de modèle, d'où le -1 pour le retirer de la manipulation.



1
votes

Étant donné un tableau de caractères char const * , nous pouvons créer un nouveau tampon avec des BYTE readwrite pour que l'API puisse éventuellement éditer:

Func(ptr.get());


2 commentaires

len + 1 Je suppose?


Bonne prise, putain!



1
votes

Dans MSVC (je suppose que c'est votre compilateur pour l'application WinAPI), vous pouvez rendre le type char non signé avec l'option / J (plus ici: https: // docs .microsoft.com / fr-fr / cpp / build / reference / j-default-char-type-is-unsigned? view = vs-2017 ). Si vous faites cela, BYTE devient le même que char et aucune conversion ne sera nécessaire.

Veuillez noter que cela peut avoir d'autres effets secondaires dans votre application.


1 commentaires

OP aurait toujours besoin d'un const_cast .