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.