2012-05-03 5 views
6

그냥 컨텍스트를 제공하기 위해 여기에 무엇을 달성하려하는지 알려줍니다. .so 파일 자체에 버전 문자열을 포함하기 위해 공유 객체 파일에 const char *를 임베드 할 예정입니다. 데이터 분석을하고 있는데,이 문자열을 통해 데이터를 생성 한 소프트웨어의 버전을 데이터에 알릴 수 있습니다. 이 모든 것이 잘 작동합니다.nm 기호 값의 오프셋?

내가 겪고있는 문제는 .so 라이브러리에서 문자열을 직접 읽으려고 할 때입니다. 나는

nm libSMPselection.so | grep _version_info 

를 사용하고

000000000003d968 D __SMPselection_version_info 

이 모든 괜찮 예상대로 (위치의 char *이 _SMPselection_version_info이라고합니다) 얻기 위해 노력했다. 그러나 지금은 파일을 열고 0x3d968을 찾고 문자열을 읽을 수있을 것으로 기대했지만, 모두 가비지입니다.

.so 파일을 열고 단순히 문자열의 내용을 검색하면 (어떻게 시작하는지 알 수 있음) 주소 0x2e0b4에서 찾을 수 있습니다. 이 주소에는 0이 종료되고 예상대로 존재합니다. (지금이 방법을 사용하고 있습니다.)

저는 컴퓨터 과학가 아닙니다. 누군가 nm에 표시된 기호 값이 올바르지 않거나 기호의 주소가 아닌 경우 기호 값은 무엇이 다른지 설명하십시오.

리눅스에

답변

2

lib를 동적으로로드하는 바이너리 (명령 행에서 이름 지정)와 기호에 대해 dlsym()을 수행하거나 명령 행에서도 가져올 수있는 바이너리를 작성하십시오. 포인터를 문자열로 변환하여 표준 출력에 인쇄합니다.

+1

이것은 좋은 생각입니다. 나는 지금 그것을 시도하고있다. 단 하나의 문제가 있습니다 : 테스트하고있는 라이브러리는 다른 라이브러리에 대해 다소 긴 의존 관계를 가지고 있습니다. 내가 dlopen으로로드하려고하면 Symbol-not-found 오류가 발생합니다. 물론 관심이있는 버전 문자열은 종속성이 없습니다. dl이 의존성을 무시하도록하려면 어떻게해야합니까? – Simon

+0

나는 체크했다. 두 개의 유스 케이스 중 하나 인 모든 종속성을로드 한 경우이 방법이 유용합니다. 아이디어를 가져 주셔서 감사합니다. – Simon

1

(나는 OSX 10.7와 Mac에서 일하고 그런데) 당신은 당신이 바이너리에서 문자열을 추출하는 데 도움이되는 '문자열'명령이있다.

http://linux.about.com/library/cmd/blcmdl1_strings.htm

HPUX에서

(그리고 나도 다른 유닉스 맛을 생각) '어떻게'라는 비슷한 명령이있다. "@ (#)"로 시작하는 문자열 만 추출하지만 문자열의 내용을 제어하는 ​​경우에는 문제가되지 않습니다.

+1

특정 기호의 내용을 얻는 데 어떻게 도움이 될까요? – PlasmaHH

+0

"what"은 좋지만 실제로는 문자열이 여러 줄로되어 있고 줄 바꿈에서 멈추고 싶습니다. strings 명령은 내 문자열이 끝나는 곳을 알려주지 않고 모든 문자열을 인쇄합니다. 또한 그것은 단지 내가하는 일인 전체 파일을 읽는 것 같습니다. 기호 항목을 읽고 문자열로 바로 이동할 수 있다면 더 우아 해 보입니다. – Simon

5

ELF 또는 이와 유사한 구조의 바이너리를 가정 할 때, ELF 헤더의 내용에 영향을받는 물건이로드되는 주소를 고려해야합니다.

바이너리에서 objdump -Fd을 사용하면 디스어셈블러가 심볼의 정확한 파일 오프셋을 표시하게 할 수 있습니다.

objdump -x을 사용하면이 로더 주소 (표준 Linux 실행 파일의 경우 보통 0x400000)를 찾을 수 있습니다.

다음으로 조심해야 할 것은 간접적 인 문자열인지 확인하는 것입니다.이 방법은 objdump -g을 사용하여 가장 쉽게 할 수 있습니다. 문자열이 간접 문자열로 발견되면 objdump -Fd에 의해 출력 된 위치에서 문자열이 아닌 주소를 찾을 수 있습니다. 여기에서 로더 주소를 다시 빼야합니다.

objdump -Fd BIN | grep VersionString 
    45152f:  48 8b 1d 9a df 87 00 mov 0x87df9a(%rip),%rbx  # ccf4d0 <acVersionString> (File Offset: 0x8cf4d0) 

objdump -x BIN 
... 
LOAD off 0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**12 
... 

그래서 우리는 파일에 0x8cf4d0보고와 hex 에디터에서 찾기 : 0x400000 빼기,

008C:F4D0 D8 C1 89 00 00 00 00 00 01 00 00 00 FF FF FF FF 

그래서 우리가 거기에 0x89C1D8을 가지고 내가 당신에게 내 바이너리 중 하나에 대한 예를 보여 드리죠 0x49c1d8을 가지고 있으며 hexeditor에서 보면 다음과 같이 나타납니다.

0049:C1D0 FF FF 7F 7F FF FF 7F FF 74 72 75 6E 6B 5F 38 30 
0049:C1E0 34 33 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

"trunk_8043"을 의미합니다.

YMMV, 특히 다른 파일 형식 인 경우에도 그렇습니다.하지만 이러한 사물이 어떻게 구성되어 있는지에 대한 일반적인 방법이며, 사마귀와 특수한 경우가 많은 세부 사항이 있습니다.

+0

그래, 고마워, 네가 대답 한 것 같아. 내가 원했던 것은 전체 파일을 스캔하지 않고 (또는 디 어셈블 링) 문자열을 가져올 수 있어야한다는 것이 었습니다. 그런데, 내 버전의 objdump에는 -F 옵션이 없습니다 (저는 GNU objdump 2.17.50.0.6-20.el5 20061020을 사용하고 있습니다). – Simon

+0

@ 시몬 : objdump의 꽤 오래된 버전입니다 (나는 2006 년이 어땠는지 기억이 안납니다). '0xccf4d0'에서 같은'0x400000' 오프셋을 뺀 값으로이 파일 오프셋을 직접 얻을 수 있습니다. 어쩌면 당신을 위해 모든 일을하는 도구가있을 수도 있고, 작은 스크립트를 쓸 수도 있습니다. – PlasmaHH

1

nm에 의해 표시되는 오프셋이 .so 파일의 오프셋이되는 이유는 무엇입니까? .so 파일은 단순히 메모리 이미지가 아닙니다. 그들은 많은 다른 정보도 포함하고 있으며, 다소 복잡한 형식을 가지고 있습니다. 유닉스에서 (적어도 대부분의 유닉스에서는) 공유 객체는 elf 형식을 사용합니다. 정보를 찾으려면 파일의 다양한 필드를 해석하여 기호가있는 위치, 세그먼트 및 해당 세그먼트가 파일에서 시작하는 위치를 찾아야합니다. (당신은 아마 그들을 읽는 단순화하는 라이브러리를 찾을 수 있습니다.)

을 또한, 당신이 내장했다고 말에 올 경우 char const*, 즉 코드가 같은 것을 포함한다 :

char const* version = "..."; 

이면 version의 주소 또는 오프셋은 가리키는 문자열 데이터가 아닌 포인터의 주소 또는 오프셋입니다. 다음과 같이 정의 :

char const version[] = "..."; 

이 문제를 해결합니다.

마지막으로 문자열에 매우 식별 가능한 패턴이 있는지 확인하고 전체 파일 을 선형으로 검색하여 가장 간단한 해결책을 찾는 것이 좋습니다.

+0

전체 파일을 스캔하는 것이 내가하는 일입니다. 그냥 덜 우아하고 뭔가를 배우고 싶습니다, 그래서 나는이 질문을 물었다. 포인터가 대신 배열을 선언하면 nm이 표시하는 기호 목록에서 사라집니다. – Simon

+1

@Simon 파일을 올바르게 구문 분석하는 것이 더 우아하지만 더 많은 작업이 필요합니다. 포인터 대신 배열을 선언 할 때 C++의 미묘함으로 인해 사라지는 이유는 const 개체가 기본적으로 내부 연결을 가지고 있기 때문입니다. 만약 당신이 'extern char const version [] = "..."'선언한다면, 이것은 일어나지 않을 것입니다; 'extern'은 외부 링키지를 강제하고 초기화는 선언이 아니라 정의로 만듭니다. –

+0

감사합니다. 물론 연결에 대해 잊어 버렸습니다! 'extern' 키워드를 사용하면 문자열이 이제 기호 테이블에 나타나고'nm '에서 가져온 주소가 실제로 찌르는 위치와 일치합니다. 이제 작동합니다. nm에서 가져온 주소로 문자열을 얻을 수 있습니다! – Simon