dd로 바이너리 패치하기


32

나는이 인용문 (아래)을 여러 번 읽었으며, 가장 최근에 여기 에서 컴파일러는 물론 모든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있습니까? 이것에 대한 역사적 의미가 있습니까?


3
물론 – od바이트 16 진 코드를위한 파일, 필요한 오프셋을 찾고, 편집을 결정하고 bs=$patchsize count=1 seek=$((offset/bs)) conv=notrunc, 패치를 바로 적용하십시오.
— mikeserv

3
누군가 부트 섹터를 덮어 쓰지 않았습니다. ;)
— Parthian Shot

@ParthianShot 사실 데비안 LiveCD의 일부로 부트 드라이브 (+ 루트)의 첫 ~ 260MB를 한 번 덮어 썼습니다. O_O하지만 난 정말 히히히 ..., 패치라고 생각하지 않는다
— Amziraro

1
또는 오히려, 그것은 디스크 파괴자의 예상되고 완전히 정상적인 행동입니다 : D
— Amziraro

답변:


73

해 봅시다. 간단한 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방금 완료했습니다.


1
이것은 훌륭합니다 ... 그리고 나는 프로덕션 환경에서 결코 만나지 않기를 바랍니다. 나는 과거에 비슷한 방법을 사용하여 마이크로 컨트롤러의 16 진수 이미지로 일련 번호를 얻었습니다. 발로 직접 촬영하는 것은 너무 쉽습니다.
— Michael Shaw

특정 바이너리를 패치하는 방법을 누군가에게 서면으로 지시하려면, "16 진 편집기에서 파일을 열고, /usr/tmp문자열을 찾고 , 바꾸고 /tmp, don '마지막 \0바이트를 잊지 말고 파일을 저장 한 다음 손가락을 교차 시키십시오.' 또는 더 나은 방법으로, 우선 상태 검사를 수행 한 다음을 호출하는 쉘 스크립트입니다 dd. 편지 소멸 공급 업체에 의한 소프트웨어의 오래 된 조각이 바로 그 때 불행하게도,이 같은 물건에 대한 필요성이 자주 발생 이 새 시스템으로 마이그레이션 할 수 있습니다.
— Guntram Blohm은 Monica

예, sed는 이런 종류의 일에 더 좋습니다. 그러나 "이 패치는 문자열을 더 짧거나 같은 길이로만 만들 수 있습니다." 수정하려는 문자열 바로 다음의 데이터에 관심이 있거나 다음 문자열을 단순히 원래 문자열의 하위 문자열로 사용할 수 없다고 가정합니다. 다시 말해, 메모리의 .strings 섹션에 있고 "/ usr \ 0 / bin / bash \ 0"이있는 경우 간단히 첫 번째를 변경하여 / usr / bin / bash로 바꿀 수 있습니다 널 바이트로 만들고 "/ usr // bin / bash"로 만듭니다 (예 :).
— Parthian Shot

2
@ParthianShot - sed의 없는 이런 종류의 일을 위해 더 나은 - 당신이 할 수없는 너무 expliciltly 정확하게 제한 sed의 읽기 / 당신이 수있는 방법으로 쓰기 버퍼 dd- 그것은 최초의 장소에 사용 된 전체 이유입니다. 함께 dd사용하면 임의의 임의의 바이트의 임의의 수를 배치 할 수 있습니다. 이것도 말할 수 없습니다 sed. 경우 dd여기에 메스처럼 사용됩니다, 당신은 적용됩니다 sed부수고 공처럼.
— mikeserv

그것은 공정한 (아주 드문 일이지만) 포인트입니다. 결과 또는 다른 임의의 특정 데이터 조각에 신경 쓰지 않고 문자열을 더 길게 만들 수있는 경우가 있습니다. 그래도 일반적인 진술을하겠습니다.
— Michael Homer

9

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

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

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


... sed바이너리 파일을 잘 처리 한다고 가정하면 gnu의 경우처럼 보이지만 ascii 파일에서만 작동 sed하는 많은 오래된 sed파일과 \0는 달리 다른 것들 (특히 입력의 경우) 과 혼동되었습니다 . 및 최대 라인 길이에 제한이 있었다.
— Guntram Blohm은 Monica

1
busybox sed는 바이너리 파일을 잘 바꿀 수있는 것처럼 보이지만 \x00대체 문자열에서 GNU가하는 방식을 이해하지 못합니다 sed. 테스트가 필요하지만 dd어떤 경우에는 훨씬 간단하기 때문에 언급 할 가치가 있다고 생각합니다 . 바이너리를 패치하는 것은 어느 쪽이든 잘못된 일입니다.
— frostschutz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.