dd로 바이너리 패치하기 있는지에 대해 계속 당황합니다 . 30

나는이 인용문 (아래)을 여러 번 읽었으며, 가장 최근에 여기 에서 컴파일러는 물론 모든dd 것을 패치하는 데 어떻게 사용할 수 있는지에 대해 계속 당황합니다 .

30 년 전에 학교에서 사용한 유닉스 시스템은 RAM과 디스크 공간이 매우 제한적이었습니다. 특히 /usr/tmp파일 시스템이 매우 작아서 큰 프로그램을 컴파일하려고 할 때 문제가 발생했습니다. 물론, 학생들은 어쨌든 “큰 프로그램”을 작성해서는 안됩니다. 큰 프로그램은 일반적으로 “어딘가”에서 복사 한 소스 코드입니다. 우리 중 많은 사람들이 복사 /usr/bin/cc/home/<myname>/cc, 그리고 사용 dd사용하는 바이너리 패치 /tmp대신/usr/tmp 더 큰이었다을. 물론, 이로 인해 문제가 더 악화되었습니다. 이러한 복사본이 차지하는 디스크 공간은 그 당시 문제가되었으며 이제는 /tmp정기적으로 채워져 다른 사용자가 파일을 편집하지 못하게합니다. 그들이 무슨 일이 있었는지 알아 낸 후, 시스템 관리자는chmod go-r /bin/* /usr/bin/* 문제를 “수정”하고 C 컴파일러의 모든 사본을 삭제했습니다.

(엠파 시스 마인)

dd사람이 페이지는 패치에 대해 아무것도 말하지 않는다 그리고이 어쨌든 할 작정 재가 될 수 있다고 생각하지 않습니다.

바이너리가 실제로 패치 될 수 dd있습니까? 이것에 대한 역사적 의미가 있습니까?



답변

해 봅시다. 간단한 C 프로그램은 다음과 같습니다.

#include <stdio.h>
int main(int argc, char **argv) {
    puts("/usr/tmp");
}

우리는 그것을 다음으로 만들 것입니다 test:

$ cc -o test test.c

실행하면 “/ usr / tmp”가 인쇄됩니다.

/usr/tmp바이너리 에서 ” “가 어디에 있는지 알아 봅시다 :

$ strings -t d test | grep /usr/tmp
1460 /usr/tmp

-t d 찾은 각 문자열의 파일에 오프셋을 10 진수인쇄합니다 .

이제 ” /tmp\0” 만있는 임시 파일을 만들어 봅시다 :

$ printf "/tmp\x00" > tmp

이제 우리는 바이너리를 가지고 있고, 변경하고자하는 문자열이 어디인지 알고, 대체 문자열을 가진 파일을 가지고 있습니다.

이제 우리는 사용할 수 있습니다 dd:

$ dd if=tmp of=test obs=1 seek=1460 conv=notrunc

이것은 tmp( ” /tmp\0“파일) 에서 데이터를 읽고 , 1 바이트의 출력 블록 크기를 사용하여 이진으로 데이터를 쓰고, 무엇이든 쓰기 전에 이전에 찾은 오프셋으로 건너 뛰며, 완료되면 파일을 명시 적으로 자르지 않습니다.

패치 된 실행 파일을 실행할 수 있습니다 :

$ ./test
/tmp

프로그램이 인쇄하는 문자열 리터럴이 변경되었으므로 이제 ” /tmp\0tmp\0” 가 포함 되지만 문자열 함수는 첫 번째 널 바이트를 보자 마자 중지됩니다. 이 패치를 사용하면 문자열을 더 짧거나 같은 길이로만 더 길게 만들 수 있지만 이러한 목적에 적합합니다.

따라서를 사용하여 패치 할 수있을뿐만 아니라 dd방금 완료했습니다.


답변

“이진 패치”의 의미에 따라 다릅니다.

dd때때로 바이너리를 사용하여 바이너리를 변경합니다 . 물론에는 그러한 기능이 없지만 dd파일을 열고 특정 오프셋에서 물건을 읽고 쓸 수 있으므로 어디에 기록 해야할지 알면 패치가 있습니다.

예를 들어 PNG 데이터가 포함 된이 바이너리가있었습니다. 사용 binwalk, 오프셋 찾을 수 dd그것으로는 (일반적으로 binwalk도 일을 추출하지만 내 복사 버그가 있었다)을 추출, 편집 gimp오프셋을 변경하면 쉽게 할 수있는 일이 있지 않은지 편집 된 파일이 동일한 크기 또는 (원래보다 작은이며, 확인 )를 사용 dd하여 변경된 이미지를 다시 제자리에 넣습니다.

$ binwalk thebinary
[…]
4194643    0x400153     PNG image, 800 x 160, 8-bit/color RGB, non-interlaced
[…]
$ dd if=nickel bs=1 skip=4194641 count=2 conv=swab | od -i
21869 # file size in this case - depends on the binary format
$ dd if=thebinary bs=1 skip=4194643 count=21869 of=theimage.png
$ gimp theimage.png
$ pngcrush myimage.png myimage.crush.png
# make sure myimage.crush.png is smaller than the original
$ dd if=myimage.crush.png of=thebinary bs=1 seek=4194643 conv=notrunc

때로는 바이너리 (예 : 경로 또는 변수 이름)의 문자열을 바꾸고 싶습니다. 을 사용하여 수행 할 수도 있지만을 사용 dd하는 것이 더 간단합니다 sed. 대체하는 문자열이 원래 문자열과 길이가 같아야 오프셋이 변경되지 않습니다.

sed -e s@/the/old/save/path@/the/new/save/path@ -i thebinary

또는 0 바이트가 추가 된 @MichaelHomer의 예제를 선택하십시오.

sed -e 's@/usr/tmp@/tmp\x00tmp@' -i test

물론 나중에 실제로 작동하는지 확인해야합니다.


답변