바이너리 파일을 C / C ++ 문자열 리터럴로 덤프하는 방법은 무엇입니까?


39

C 소스 코드에 포함하고 싶은 바이너리 파일이 있는데 (임시 테스트 목적으로) 파일 내용을 다음과 같이 C 문자열로 얻고 싶습니다.

\x01\x02\x03\x04

od또는 hexdump유틸리티 를 사용하여 가능 합니까? 필요하지는 않지만 문자열이 16 입력 바이트마다 다음 줄로 줄 바꿈되고 각 줄의 시작과 끝에 큰 따옴표를 포함하면 훨씬 좋습니다!

문자열에 null ( \x00) 이 포함되어 있음을 알고 있으므로 코드에서 문자열의 길이를 지정하여 이러한 바이트가 문자열을 일찍 종료하지 못하게해야합니다.



나는 비슷한 것을 원하지만 ascii 인쇄 가능한 글리프를 유지하고 1-127, 따옴표, 백 슬래시, 널 등을 이스케이프 처리합니다.
把 友情 留 在 无 盐

답변:


10

당신 이 원하는 것을 거의 할 수 hexdump있지만 따옴표와 단일 백 슬래시를 형식 문자열로 얻는 방법을 알 수 없습니다. 그래서 나는 약간의 사후 처리를 수행 sed합니다. 보너스로 각 줄을 4 칸 들여 쓰기했습니다. :)

hexdump -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/.*/    "&"/'

편집하다

Cengiz Can이 지적했듯이 위의 명령 줄은 짧은 데이터 줄에 잘 맞지 않습니다. 여기에 새로운 개선 된 버전이 있습니다 :

hexdump -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/\\x  //g; s/.*/    "&"/'

주석에 Malvineous가 언급했듯이 -v자세한 hexdump바이트 옵션을 전달하여 동일한 바이트의 긴 실행을 약자 로 줄여야합니다 *.

hexdump -v -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/\\x  //g; s/.*/    "&"/'

입력이 16 바이트보다 짧은 경우 중복되고 유효하지 않은 요소가 생성됩니다.
Cengiz는

@CengizCan : : oops :! 더 낫습니까?
PM 2Ring

1
-v옵션 을 추가해야합니다 hexdump. 그렇지 않으면 동일한 입력 바이트를 오래 실행하면 출력 라인이 표시 "*"됩니다.
Malvineous

@Malvineous 좋은 지적! 내 답변을 수정했습니다. 진심으로 감사합니다 (그리고 내 대답을 받아 주셔서 감사합니다).
오후 2Ring

66

xxd이를위한 모드가 있습니다. -i/ --include옵션 것입니다 :

C의 출력은 파일 스타일을 포함합니다. xxd가 stdin에서 읽지 않는 한 완전한 정적 배열 정의가 작성됩니다 (입력 파일 이름을 따서 명명 됨).

#included 로 파일에 덤프 한 다음 foo다른 문자 배열처럼 액세스 하거나 링크 할 수 있습니다. 또한 배열 길이의 선언도 포함합니다.

출력은 80 바이트로 랩핑되며 기본적으로 직접 작성하는 것과 유사합니다.

$ xxd --include foo
unsigned char foo[] = {
  0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
  0x21, 0x0a, 0x0a, 0x59, 0x6f, 0x75, 0x27, 0x72, 0x65, 0x20, 0x76, 0x65,
  0x72, 0x79, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x21, 0x20,
  0x57, 0x65, 0x6c, 0x6c, 0x20, 0x64, 0x6f, 0x6e, 0x65, 0x2e, 0x0a
};
unsigned int foo_len = 47;

xxd다소 이상하게도 vim분포의 일부 이므로 이미 배포했을 가능성이 큽니다. 그렇지 않은 경우 바로 그 곳에서 얻을 수 있습니다 vim. 소스에서 자체적으로 도구를 빌드 할 수도 있습니다 .


좋은! 나는 내가 xxd를 가지고 있다는 것을 몰랐다. 이제 다음에 필요할 때 존재한다는 것을 기억해야합니다 ... 또는 아마도 파이썬에서 필요한 기능을 복제 할 것입니다. :)
PM 2Ring

objcopy더 좋을 것입니다
Monica와의 가벼운 경주

@LightnessRacesinOrbit objcopy는 OP가 바이너리 파일을 실행 파일과 객체 파일로 링크 할 수있게 해주지 만 유용하지만 여기서 정확히 요구되는 것은 아닙니다.
Wander Nauta

1
@WanderNauta : 액세스를 원하는만큼 당신은 거의 같은 방식으로 액세스 할 foo/ foo_len여기에, 그리고 저장 공간을 낭비 크게 없을 것이다. OP가 더 좋을 것이며 objcopy자신의 요구 사항에 적합 하다고 확신합니다 .
Monica와의 가벼움 경주

2
objcopy주변에 있으면 괜찮지 만 휴대용이 아니며 출력이 훨씬 적습니다. 확실히 훌륭한 영구 솔루션의 일부일 수는 있지만 여기서는 문제가되지 않습니다.
Michael Homer

3

xxd 좋지만 결과는 매우 장황하며 많은 저장 공간이 필요합니다.

objcopy;를 사용하여 실질적으로 동일한 것을 얻을 수 있습니다 . 예 :

objcopy --input binary \
    --output elf32-i386 \
    --binary-architecture i386 foo foo.o

그런 다음 foo.o프로그램에 연결 하고 다음 기호를 사용하십시오.

00000550 D _binary_foo_end
00000550 A _binary_foo_size 
00000000 D _binary_foo_start

이것은 문자열 리터럴이 아니지만 컴파일 중에 문자열 리터럴이 바뀌는 것과 본질적으로 동일합니다 (문자열 리터럴 은 실제로 런타임에 존재하지 않는다는 것을 고려하십시오 . 실제로 다른 답변은 실제로 문자열 리터럴을 제공하지 않습니다 컴파일 타임에도)와 거의 같은 방식으로 액세스 할 수 있습니다.

unsigned char* ptr = _binary_foo_start;
int i;
for (i = 0; i < _binary_foo_size; i++, ptr++)
   putc(*ptr);

단점은 객체 파일을 호환 가능하게 만들기 위해 대상 아키텍처를 지정해야하며 이는 빌드 시스템에서 사소하지 않을 수 있다는 것입니다.


2

정확히 당신이 요구 한 것이어야합니다 :

hexdump -v -e '"\\" "x" 1/1 "%02X"' file.bin ; echo

0

이것은 본질적으로 똑같은 일을하는 간단한 유틸리티입니다 (원래 스택 오버플로에 게시 됨 ).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LENGTH 80

int main(void)
{
    FILE *fout = fopen("out.txt", "w");

    if(ferror(fout))
    {
        fprintf(stderr, "Error opening output file");
        return 1;
    }
    char init_line[]  = {"char hex_array[] = { "};
    const int offset_length = strlen(init_line);

    char offset_spc[offset_length];

    unsigned char buff[1024];
    char curr_out[64];

    int count, i;
    int line_length = 0;

    memset((void*)offset_spc, (char)32, sizeof(char) * offset_length - 1);
    offset_spc[offset_length - 1] = '\0';

    fprintf(fout, "%s", init_line);

    while(!feof(stdin))
    {
        count = fread(buff, sizeof(char), sizeof(buff) / sizeof(char), stdin);

        for(i = 0; i < count; i++)
        {
            line_length += sprintf(curr_out, "%#x, ", buff[i]);

            fprintf(fout, "%s", curr_out);
            if(line_length >= MAX_LENGTH - offset_length)
            {
                fprintf(fout, "\n%s", offset_spc);
                line_length = 0;
            }
        }
    }
    fseek(fout, -2, SEEK_CUR);
    fprintf(fout, " };");

    fclose(fout);

    return EXIT_SUCCESS;
}

1
입력 및 출력 예제도 제공하면 답변이 더 유용합니다.
not2qubit

0

파이썬에 있다면, 변수 "buff"에로드하고 다음과 같이 사용하십시오 :

buff2 = buff.encode("hex")
print ("0x"+", 0x".join([buff2[i:i+2] for i in range(0,len(buff2),2)]))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.