1

バイナリファイルにパッチを適用するためのコードをいくつか作成しました。パッチは、00FF00:A155F3;9210BCのように16進値のASCII表現で区切られています。

私の問題は、16進数の値を正確に256だけ誤って計算していることですが、区切り文字':'と';'の間だけです。コード内の位置に関係なく同じhex2char()関数を使用しているため、この1つの特定の領域で失敗する理由がわかりません。私はそれに多くの時間を無駄にする代わりに、stackoverflowにサインアップして助けを得るだろうと考えました。

外部ライブラリを使用したくない、stdio.hとstdlib.h以外のものを含めたくない(EOFまでsys / stat.h、fread()とrealloc()を削除します。しかし、それは別の問題であり、私はそれについて心配していません)

これがコードです。私のメインループは終わりに近づいていて、悪い出力が得られる場所を明確にマークしています。

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>


//I'll populate this later
struct _pos {
    unsigned pos;
} pos;


//raise x to the power of y
unsigned power( unsigned x, unsigned y )
{
    if ( y == 0 )
    {
        return 1;
    }
    else
    {
        return x * power( x, y - 1 );
    }
}

//convert ascii hex values to integers
unsigned h2i(const char *input, int len) {
    unsigned retval = 0;
    char cur = 0;
    int loops = 0;
    while (0 < len) {
        cur = input[--len];
        //check if we are out of the range hex would be in
        //we assume capital letters A - F
        if ( cur < 0x30 || cur > 0x46 ) {
            printf("Hex out of range: %X\n", cur);
            exit(EXIT_FAILURE);
        }

        //numerical
        if ( cur < 0x3a ) {
            cur -= 0x30;
        }

        //alphabetical
        else {
            cur -= 0x37;
        }

        retval += (cur * power(16, loops));
        ++loops;
        }
    return retval;
}

//take 2 chars from the input and get a hex value from it
char hex2char(const char *input) {
    char buff[2];
    buff[0] = input[pos.pos++];
    buff[1] = input[pos.pos++];
    printf("\nBUFF: %c%c : POS: %i\n", buff[0], buff[1], pos.pos);
    return h2i(buff, 2);
}


//turn a delimiter terminated string into a number
unsigned hex2int(const char *input, char delimiter) {
    int offset = 0;
    char buff[13]; //max int length if represented by string

    //copy string into the buffer
    while (input[offset] != delimiter) {
        if (offset == 12) {
            printf("parse error: offset\n");
            exit(EXIT_FAILURE);
        }
        buff[offset] = input[offset];
        ++offset;
    }
   //printf("BUFF: %s : OFFSET: %i\n", buff, offset);
    pos.pos += offset;
    return h2i(buff, offset);

}

char *fast_cache( char *Filename, unsigned long *size ) {
    FILE *FilePointer;
    FilePointer = fopen( Filename, "r" );
    if ( FilePointer != NULL ) {
        char *ptr;
        struct stat FileStat;
        fstat( fileno( FilePointer ), &FileStat );
        *size = FileStat.st_size;
        ptr = ( char * ) malloc( *size );
        fread( ptr, 1, *size, FilePointer );
        fclose( FilePointer );
        return ptr;
        }
    else {
        return NULL;
        }
    }


int main(int argc, char **argv)
{
    // print greeting
    printf("Hello World!\n");

    unsigned long size;
    char *file = fast_cache(argv[1], &size);
    if (file == NULL) {
        printf("You must specify an input!\n");
        exit(EXIT_FAILURE);
    }

    //okay, patchfile found, opened, and cached, time to convert
    pos.pos = 0; //file position

    //this will be the output, unused right now
    FILE *out = fopen("output", "w");
    //a line in the file is formatted like this
    //0000FF:A9DF23;A7FF11
    unsigned fileoffset = 0;
    unsigned trash = 0;


    //loop through all lines in the patchfile
    while (pos.pos < size) {
        fileoffset = hex2int(file, 0x3a);
        ++pos.pos;
        printf("offset: %u CUR: %c\n", fileoffset, file[pos.pos]);
        while(file[pos.pos] != 0x3b ) {
            //check current values with file values
            //not implimented yet, i just print it out

///////////////////////////////////////////////////////////////////
///////////This is the issue right here///////////////////////////
//printf prints a near MAX_INT number hex value > 0xFFFFFF00
//and it is off by exactly 256 every time, but that would mean overflowing
            printf("%X ", hex2char(file));

        }
//////////////////////////////////////////////////////////////////
//but right here until EOF, everything is fine and works normally
//and it's the same freaking function

        printf("\nfound delimiter: %c @ %u\n", file[pos.pos], pos.pos);
        ++pos.pos;

        //second half of the line
        while(file[pos.pos] != '\n' && pos.pos < size) {
            printf("%X ", hex2char(file));
        }
        //eat the new line if there is one
        ++pos.pos;
        printf("\nLine complete\n");
    }

    return 0;
}
4

2 に答える 2

3

C で printf を使用すると、文字が int に昇格されます。それらは符号なし文字であるため、残りのビットをマスクする必要があります。

交換:

printf("%X ", hex2char(file));

と:

printf("%X ", hex2char(file) & 0xff);

この問題の完全な説明は 、C での 16 進文字の印刷とhttp://en.wikipedia.org/wiki/Sign_extensionに あります。

これをアセンブリに実装する必要がある場合は、pow 関数を単純なビット シフト操作に置き換えることをお勧めします。X << 4 == X * 16. また、マイクロコントローラーやその他の組み込みシステムでは、16 ビット システムを見つけることができることに注意してください。この場合、int のサイズは異なる場合があります。

于 2012-10-09T08:02:59.120 に答える
2

文字列を整数に変換するコードは...非常に複雑です。

必要なのは、値を 4 ビット左にシフトするpower()ようなものだけの場合のように、(再帰的な!) 関数を使用するのは本当にやり過ぎです。x <<= 4

コードを詳しく説明するのではなく、16 進文字列を次のような整数関数に置き換えてみてください。

/* Parse hexadecimal number at s into value stored in v. Returns pointer to first
 * character that is not part of the number. Doesn't protect against overflow.
*/
const char * parse_int_hex(const char *s, unsigned long *v)
{
  *v = 0;
  for(; ; s++ )
  {
    char here = *s;
    unsigned long dv;
    if( here >= '0' && here <= '9' )
      dv = here - '0';
    else if( here >= 'a' && here <= 'f' )
      dv = 10 + here - 'a';
    else if( here >= 'A' && here <= 'F' )
      dv = 10 + here - 'A';
    else
      return s;
    *v <<= 4;
    *v += dv;
  }
  return s;
}

上記には依存関係がないため、文字チェックが非常に面倒です。:) これは、単純な 16 進数から整数への変換ルーチンに期待されるサイズとほぼ同じです。

于 2012-10-09T08:03:08.823 に答える