Docker 이미지를 Dockerfile로 리버스 엔지니어링
Docker 이미지가 데이터를 저장하는 방법의 내부를 검사하여 도커 이미지를 리버스 엔지니어링합니다.
TL;DR
이 이야기에서는 Docker 이미지가 데이터를 저장하는 방법, 도구를 사용하여 이미지의 다양한 측면을 보는 방법, Python Docker API를 사용하여 생성하는 Dedockify 와 같은 도구를 만드는 방법을 살펴봄으로써 Docker 이미지를 리버스 엔지니어링할 것입니다. Dockerfile.

소개
Docker Hub 및 TreeScale 과 같은 공개 Docker 레지스트리 가 대중화됨에 따라 관리자와 개발자가 알 수 없는 엔터티가 생성한 이미지를 다운로드하는 것이 점점 더 보편화되고 있습니다. 대부분의 경우 편의성이 인식된 위험보다 우선합니다. 경우에 따라 Docker 이미지가 공개되면 목록, git 저장소 또는 관련 링크를 통해 직접 제공됩니다. 더 자주 Dockerfile이 제공되지 않습니다. Dockerfile을 사용할 수 있는 경우 미리 빌드된 이미지가 Dockerfile과 관련이 있거나 사용하기에 안전하다는 보장이 거의 없습니다.
보안 취약점에 관심이 없을 수도 있습니다. 최신 버전의 Ubuntu에서 실행되도록 좋아하는 이미지 중 하나를 업데이트하고 싶을 수 있습니다. 또는 컴파일 시간 동안 바이너리를 생성하는 데 더 적합한 다른 배포판용 컴파일러가 있기 때문에 조금 더 최적화된 이미지를 릴리스해야 한다는 제어할 수 없는 강박감을 느낄 수도 있습니다.
이유가 무엇이든 이미지의 Dockerfile을 복구하는 옵션이 있습니다. Docker 이미지는 블랙박스가 아닙니다. Dockerfile을 재구성하는 데 필요한 대부분의 정보는 검색할 수 있습니다. Docker 이미지 내부를 살펴보고 내부를 검사하면 미리 빌드된 임의의 컨테이너에서 Dockerfile을 면밀히 재구성할 수 있습니다.
이 스토리에서는 이 스토리 를 위해 제공되는 맞춤형 Python 스크립트인 Dedockify 와 Docker 이미지 탐색 도구인 Dive 라는 두 가지 도구를 사용하여 이미지에서 Dockerfile을 재구성하는 방법을 보여줍니다 . 사용되는 기본 프로세스 흐름은 다음과 같습니다.

잠수 사용

이미지가 구성되는 방식을 빠르게 이해하기 위해 Dive를 사용하여 일부 고급 및 잠재적으로 익숙하지 않은 Docker 개념을 배웁니다. Dive 도구는 Docker 이미지의 각 레이어를 검사합니다.
Dockerfile
테스트에 사용할 수 있는 간단하고 따라하기 쉬운 것을 만들어 봅시다 .
이 스니펫을 빈 디렉토리에 직접 넣습니다.
cat > Dockerfile << EOF ; touch testfile1 testfile2 testfile3
FROM scratch
COPY testfile1 /
COPY testfile2 /
COPY testfile3 /
EOF
$ ls
Dockerfile testfile1 testfile2 testfile3
docker build . -t example1
Sending build context to Docker daemon 3.584kB
Step 1/4 : FROM scratch
--->
Step 2/4 : COPY testfile1 /
---> a9cc49948e40
Step 3/4 : COPY testfile2 /
---> 84acff3a5554
Step 4/4 : COPY testfile3 /
---> 374e0127c1bc
Successfully built 374e0127c1bc
Successfully tagged example1:latest
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
example1 latest 374e0127c1bc 31 seconds ago 0B
소스 이미지가 없음을 이미지 크기로 볼 수 있습니다. 소스 이미지 대신 소스 이미지 scratch
로 0바이트 빈 이미지를 사용하도록 Docker에 지시한 것을 사용했습니다. 그런 다음 세 개의 추가 0바이트 테스트 파일을 빈 이미지에 복사하여 빈 이미지를 수정한 다음 변경 사항에 example1
.
이제 Dive로 새로운 이미지를 살펴보겠습니다.
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive:latest example1
Unable to find image 'wagoodman/dive:latest' locally
latest: Pulling from wagoodman/dive
89d9c30c1d48: Pull complete
5ac8ae86f99b: Pull complete
f10575f61141: Pull complete
Digest: sha256:2d3be9e9362ecdcb04bf3afdd402a785b877e3bcca3d2fc6e10a83d99ce0955f
Status: Downloaded newer image for wagoodman/dive:latest
Image Source: docker://example-image
Fetching image... (this can take a while for large images)
Analyzing image...
Building cache...
Dive screenshot by author.

각 레이어를 스크롤하면서 오른쪽의 내용이 변경되는 것을 볼 수 있습니다. 각 파일이 빈 Docker 이미지에 복사되면서 scratch
새 레이어로 기록되었습니다.

또한 각 레이어를 생성하는 데 사용된 명령을 볼 수 있습니다. 소스 파일과 업데이트된 파일의 해시 값도 볼 수 있습니다.
섹션 의 항목을 기록 Command:
하면 다음이 표시됩니다.
#(nop) COPY file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in /
#(nop) COPY file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in /
#(nop) COPY file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in /
도커 역사
dive 와 같은 타사 도구 외에 즉시 사용할 수 있는 도구는 입니다 docker history
. docker history
이미지 에 명령을 사용하면 example1
해당 이미지를 생성하기 위해 Dockerfile에서 사용한 항목을 볼 수 있습니다.
docker history example1
IMAGE CREATED CREATED BY SIZE COMMENT
374e0127c1bc 25 minutes ago /bin/sh -c #(nop) COPY file:aa717ff85b39d3ed… 0B
84acff3a5554 25 minutes ago /bin/sh -c #(nop) COPY file:2a949ad55eee33f6… 0B
a9cc49948e40 25 minutes ago /bin/sh -c #(nop) COPY file:e3c862873fa89cbf… 0B
$ docker history example1 --no-trunc
IMAGE CREATED CREATED BY SIZE COMMENT
sha256:374e0127c1bc51bca9330c01a9956be163850162f3c9f3be0340bb142bc57d81 29 minutes ago /bin/sh -c #(nop) COPY file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in / 0B
sha256:84acff3a5554aea9a3a98549286347dd466d46db6aa7c2e13bb77f0012490cef 29 minutes ago /bin/sh -c #(nop) COPY file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in / 0B
sha256:a9cc49948e40d15166b06dab42ea0e388f9905dfdddee7092f9f291d481467fc 29 minutes ago /bin/sh -c #(nop) COPY file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in / 0B
Python용 Docker 엔진 API 사용
Docker는 Python 내에서 Docker를 완전히 제어할 수 있는 Docker Engine API용 Python 라이브러리를 출시했습니다 . docker history
다음 예제에서는 다음 Python 3 코드를 실행 하여 사용한 것과 유사한 정보를 복구할 수 있습니다 .
#!/usr/bin/python3
import docker
cli = docker.APIClient(base_url='unix://var/run/docker.sock')
print (cli.history('example1'))
[{'Comment': '', 'Created': 1583008507, 'CreatedBy': '/bin/sh -c #(nop) COPY file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in / ', 'Id': 'sha256:374e0127c1bc51bca9330c01a9956be163850162f3c9f3be0340bb142bc57d81', 'Size': 0, 'Tags': ['example:latest']}, {'Comment': '', 'Created': 1583008507, 'CreatedBy': '/bin/sh -c #(nop) COPY file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in / ', 'Id': 'sha256:84acff3a5554aea9a3a98549286347dd466d46db6aa7c2e13bb77f0012490cef', 'Size': 0, 'Tags': None}, {'Comment': '', 'Created': 1583008507, 'CreatedBy': '/bin/sh -c #(nop) COPY file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in / ', 'Id': 'sha256:a9cc49948e40d15166b06dab42ea0e388f9905dfdddee7092f9f291d481467fc', 'Size': 0, 'Tags': None}]

도킹 해제
몇 단계 더 나아가 보겠습니다. 이 이미지를 Dockerfile로 리버스 엔지니어링하려면 모든 것을 구문 분석하고 읽을 수 있는 형식으로 다시 포맷해야 합니다. 이 이야기의 목적을 위해 다음 Python 3 코드를 사용할 수 있으며 GitHub 의 Dedockify 리포지토리에서 얻을 수 있습니다. 감사 의 말은 모든 위대한 원본 기초 작업과 코딩 에 대해 LanikSJ 에게 전달 됩니다.
from sys import argv
import docker
class ImageNotFound(Exception):
pass
class MainObj:
def __init__(self):
super(MainObj, self).__init__()
self.commands = []
self.cli = docker.APIClient(base_url='unix://var/run/docker.sock')
self._get_image(argv[-1])
self.hist = self.cli.history(self.img['RepoTags'][0])
self._parse_history()
self.commands.reverse()
self._print_commands()
def _print_commands(self):
for i in self.commands:
print(i)
def _get_image(self, img_hash):
images = self.cli.images()
for i in images:
if img_hash in i['Id']:
self.img = i
return
raise ImageNotFound("Image {} not found\n".format(img_hash))
def _insert_step(self, step):
if "#(nop)" in step:
to_add = step.split("#(nop) ")[1]
else:
to_add = ("RUN {}".format(step))
to_add = to_add.replace("&&", "\\\n &&")
self.commands.append(to_add.strip(' '))
def _parse_history(self, rec=False):
first_tag = False
actual_tag = False
for i in self.hist:
if i['Tags']:
actual_tag = i['Tags'][0]
if first_tag and not rec:
break
first_tag = True
self._insert_step(i['CreatedBy'])
if not rec:
self.commands.append("FROM {}".format(actual_tag))
__main__ = MainObj()
여기까지 완료했다면 두 개의 이미지가 있어야 wagoodman/dive
합니다 example1
.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
example1 latest 374e0127c1bc 42 minutes ago 0B
wagoodman/dive latest 4d9ce0be7689 2 weeks ago 83.6MB
$ python3 dedockify.py 374e0127c1bc
FROM example1:latest
COPY file:e3c862873fa89cbf2870e2afb7f411d5367d37a4aea01f2620f7314d3370edcc in /
COPY file:2a949ad55eee33f6191c82c4554fe83e069d84e9d9d8802f5584c34e79e5622c in /
COPY file:aa717ff85b39d3ed034eed42bc1186230cfca081010d9dde956468decdf8bf20 in /
비교를 위해 이미지와 동일한 작업을 수행해 보겠습니다 wagoodman/dive
.
$ python3 dedockify.py 4d9ce0be7689
FROM wagoodman/dive:latest
ADD file:fe1f09249227e2da2089afb4d07e16cbf832eeb804120074acd2b8192876cd28 in /
CMD ["/bin/sh"]
ARG DOCKER_CLI_VERSION=
RUN |1 DOCKER_CLI_VERSION=19.03.1 /bin/sh -c wget -O- https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_CLI_VERSION}.tgz | tar -xzf - docker/docker --strip-component=1 \
&& mv docker /usr/local/bin
COPY file:8385774b036879eb290175cc42a388877142f8abf1342382c4d0496b6a659034 in /usr/local/bin/
ENTRYPOINT ["/usr/local/bin/dive"]
Dedockify 제한 테스트
Dockerfile
기본 이미지를 명시적으로 정의 하는 예제를 만들어 실험해 봅시다 . 이전에 했던 것처럼 빈 디렉터리에서 명령줄에서 직접 다음 스니펫을 실행합니다.
cat > Dockerfile << EOF ; touch testfile1 testfile2 testfile3
FROM ubuntu:latest
RUN mkdir testdir1
COPY testfile1 /testdir1
RUN mkdir testdir2
COPY testfile2 /testdir2
RUN mkdir testdir3
COPY testfile3 /testdir3
EOF
$ docker build . -t example2
Sending build context to Docker daemon 3.584kB
Step 1/7 : FROM ubuntu:latest
---> 72300a873c2c
Step 2/7 : RUN mkdir testdir1
---> Using cache
---> 4110037ae26d
Step 3/7 : COPY testfile1 /testdir1
---> Using cache
---> e4adf6dc5677
Step 4/7 : RUN mkdir testdir2
---> Using cache
---> 22d301b39a57
Step 5/7 : COPY testfile2 /testdir2
---> Using cache
---> f60e5f378e13
Step 6/7 : RUN mkdir testdir3
---> Using cache
---> cec486378382
Step 7/7 : COPY testfile3 /testdir3
---> Using cache
---> 05651f084d67
Successfully built 05651f084d67
Successfully tagged example2:latest
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
example2 latest 05651f084d67 2 minutes ago 64.2MB
example1 latest 374e0127c1bc 1 hour ago 0B
ubuntu latest 72300a873c2c 9 days ago 64.2MB
wagoodman/dive latest 4d9ce0be7689 3 weeks ago 83.6MB
$ python3 dedockify.py 05651f084d67
FROM ubuntu:latest
RUN /bin/sh -c mkdir testdir1
COPY file:cc4f6e89a1bc3e3c361a1c6de5acc64d3bac297f0b99aa75af737981a19bc9d6 in /testdir1
RUN /bin/sh -c mkdir testdir2
COPY file:a04cdcdf5fd077a994fe5427a04f6b9a52288af02dad44bb1f8025ecf209b339 in /testdir2
RUN /bin/sh -c mkdir testdir3
COPY file:2ed8ccde7cd97bc95ca15f0ec24ec447484a8761fa901df6032742e8f1a2a191 in /testdir3
블라인드 프리스타일 Dockerfile 재구성
이제 이미 논의한 도구를 사용하여 적절한 방법으로 Docker 컨테이너를 리버스 엔지니어링해 보겠습니다. 우리가 사용할 컨테이너는 위의 예에서 수정되었습니다. 우리의 이전 Dockerfile
은 생성하도록 수정되었습니다 example3
. 작은 바이너리를 추가하여 이미지를 기능적으로 만들었습니다. 어셈블리 소스 코드는 Dedockify GitHub 리포지토리 에서 사용할 수 있습니다 . 이 이미지는 너무 작기 때문에 빌드하거나 가져올 필요가 없습니다. 아래 스니펫을 사용하여 전체 컨테이너를 Docker 환경에 바로 복사하여 붙여넣음으로써 명령줄 기술을 과시할 수 있습니다.
uudecode << EOF | zcat | docker load
begin-base64 600 -
H4sICMicXV4AA2V4YW1wbGUzLnRhcgDtXVtvG8cVVnp56UN/QJ/YDQokgETN
zJkrgTykjgsbDSzDURMkshDM5YzFhiJVkkpiCELzH/pP+tYfkf/UsxRNXdxI
spe7lqv5IJF7PTM7Z87MmY9nZxgL2qG1DkN2nkXmtTecQwYrMMfsBHgXgFuV
eXLCI5c26sxdNHQsie2Nm8GYZEYp+l7g6vdim4MWBrgyBjaY4MbIjZ66hezG
OJ7N/ZSyMp1M5tddd9P5qw/3noA11f+XD5998XjnybVpcMa0lNfoH67oHxiI
jV4nhXjP9c/7701WC1pAY/v/+2wyvimNG+zfgLpi/0KbYv+d4KQapmpQNa0G
1WZ15Kc4npMsr7JUjGGMyLUzPEXJc1RCWqFkTtoEL5TgEaLSKlmOiXHnUSlK
jYsQSFacop9jnTHuDNtinP52GRss/r6pL5iM5344xum3tJWHL6rBSfVoMpuP
/SHSXXTFZ5NDuuB8/28znJ5tfTqf+3jwxTwNx9Ug+9EMLxybHM9fP4jT6erg
7vzlanvnCMeX5Sz2dsYRV0cejr+vBuPj0WizenCYXm0+PvQvlhn7cjI6PsTZ
qzNfTabfDccvPhsuc/twPJ++PJoM66I9u2Jn/Ofj4Wgl6nMfcLS8/XSzmtBm
NRqOj3+sTm+h/8b2P/IvcdqvbeiX07je/uXr/h9oZor9dwF/dHQbF74R3sz/
F1RfuKbLi//fAWr993846C/+J0f/aCONRR9/g/4vbXNQShb7LygoKGgTTDkP
1tiEUvkgJajgnTZRA0pAplFqZ1m02hqXjc4+aaVTztx4pzywfvPxH7X1V/0/
oZgu7X8XOKn8NB4M5xjnx9N6ROIPk5ZnI6y7P67aq55+uvvok+3j2XR7NIl+
tD0Lw/Hgwv5q9/zEYuNslz6q/f85MJsd0CBVD4SHEDhGkM4LDIqHQN4JjU5s
5NqiJguRAr3nKpgICoRhyLNiCgHQOLxhfLdN7teVMd7e4uD2AY5Gkzpv14/2
VuPgegyvDA3aOATr5cJkJUs0tMsRacytE6MsGZnp/piCEMaiijHmJJOIihvN
bh5WX0zh/7kqkA5od3t2QI+yFenjw4/Gk6OPe7Wqnuw++/rpzuMnu7295xdU
9bzar29/X6rPyenpRZZFMMG2GGwxsStgoPhAQF8KrZ1grqZb0iR+R5Xie5zO
hpPxgpbpM+hrOnUwnM0nU1LY3sm1AnnfOXCgDDPfnDM834aX9XOclXZvK/aW
Jf3VzrO/fvb4WW97jjPS95RXp5vXyxd9Qd0MSCnsLeQ/2Hn6dS8PRzgAIbLL
TiBEJ9Ej8hRZEmCURW6CcTaD8+h18BhtdsrJIFDGmBigS6w3HPfqTNbCeO8W
2SQjVBK4lW9RDOIW8hUZv+PG8XdWDOI2xWA4mYGkKvYWxQC3kO+YdMYxod5Z
McDNxQB9Zpkg38iJNymG2uxvFi005+RJwRsVQAAIkmURmaF+gwUXvAZjApis
tWaSJyWFoAaKOS1DFJrKR0omQSSNVvO6ABaNz20e/mITc0MOe9c1vJsVHh7N
X3674CKrwXx6jKf7l6jQzar233Ld8lXzl0d1E724eFY3bsOcvx2mWd14Lttt
riUXQXJAZFJn5MLriMHJTA6yT44zHZjHQJ2qZM5watCpBeeevFdMdANJXUkC
7ZMxjCq7TI6cbW+zUkEpqj/RMrBeWInCUuFqj3QZTxays9RrBNT+XBJDh2Qw
wQkfqXcAqjZK5RA5SNIJzywKSTKTMGiYjkoknwJjzgVg1vBwLilYbbwhFzsz
LYTTwqNgRiMEZhMYK7zztZ9gmHUZap8/0WOROCXRenUhT1Q8IlhltBbOihhR
ZhOtoucgwVRolD3DkqprS6bHZzlbmxMNOBJGRYVxLsmDcSGZJBkTjkdlEtW3
IKj4nA0oUJHDYgP5MZQ3qjHKZCrDqJSylvwZhAtPF5PRMfJEt4I0kjvms/Qq
U4VVnp6O6jD3PJpaujKcLqJqaNF5TlrR5lxS5jQ2IfVRv22MAhbInjAaiNIp
zkSGCAacVmAj0IPWDVoKPFCjQMXi0VX7p7eh4N8phI70kElxeg7vhJIKZYpa
qOy9J9Vpck3Qkx2I2qOMIUrSQ46GKrzkqHRb8R+cF/63CzTWfyvxH8LI8vtP
JyjxH/cbje1/DfEfWvDX4j8YL/bfBZbxH02rQYnZ6DBmY51obP/txH8oUX7/
7QSv+LU2g0DezP/nVF+EBij+fxdY6b/FIJC6PN4s/kOqWv/F/gsKCgrag2Jg
EIxFl3RyIWQB2bjkDIiYFeTIUuLJy6SNNUG4wKPl3GeXEgSfWuL/BNTxv6X/
bx+N9d/O+18gVen/u0Dh/+43Gtt/K+9/gWDF/jvBkv9rWg0uvf/lBSZQEqIi
YUoB50E7iU4JFD4ESbcok5Kq6SWbIWjFpbFSCOmUYaxwiR1yiY3tvxX+T3JR
3v/sBK8Cy+4O/yfO+L/y/lcnWOn/rvF/hf8vKCgoaBXGQgwYvEKWwNmY0euo
As/cks/mFGMgBI+BfD7jaJtrHaMnhx1ZMAF9a/M/6dL/d4HG+m9r/qfS/3eC
wv/dbzS2/7bmfyr23wmW/F/TanCR/7PKBZAyeI7SuGDqd0Y9ahVYZj6nJFFq
pZS2UieBDAC05HRxNBKE06nwfx3yf43tv6X5n3iJ/+0Er96ovHP8X/H/O8FK
/3eN/yu//xUUFBS0iqbOekv8nzSs9P9doLH+23n/V4ky/1cnKPzf/UZj+2+H
/wNd7L8TLPm/NXB2K/5vDbGEhf/riv9rbP/t8H/Ayvt/naDE/xX9L/S/mrxv
/Wnc7P9f1P+C/5OyxP8WFBQUtIqmizW1Ff9X+v9u0Fj/Lc3/Z4r/3wkK/3e/
0dj+W4r/K/P/dIMl/7eGNRtX/N8aYgkL/9cV/9fY/lua/0+xYv9doMT/Ff0v
9L9atWL9abwV/1fi/wsKCgpaRdPJetqK/6vX/y39f/torP+W4v94+f2vExT+
736jsf23FP+niv13glf8X/M5+1b8X1lL5H3i/5rafzv8n9Bl/a9OcPfW/1jy
f8X/7wQr/a/WMF5/Gm/F/xX+v6CgoKBVJPK8tUkQIUjIXCXMBoJj0oPO3Btu
jJc86SyRWaFFDOhQ8QxKJ8uya2n9D6bK+h+doLH+25n/j/My/0cnKPzf/UZj
+2/O/wmQr63/a0r8TzdY8n9Nq8FF/o+xoB1a6zBk51lkXpMADhmswByzE+Bd
AG5V5skJj1zaSKm4aOhYEpf4P8EE22KwxcSugIHiAwF9KbR2grlLRGCdsKrf
XuUQrJe25hYlS5SRHDFpoxNDACOzDxhToCpmUcUYc5JJRMWNZjfzihdTuGsc
41719NPdR59sH8+m26NJ9KPtWRiOBxf2V7vnJxYbZ7v0Ue0vScq9qt7dnh3Q
o2xF+vjwo/Hk6ONezUc+2X329dOdx092e3vPq21/dLR9gKPR5Hm1X9/+itic
HXih9EB4CIFjBOm8wKB4CIxMnRkbubaokRoGgd5zFUwEBcIw5FkxRbpC4/AG
frRO/gpHunchT3WGfoEtPTk93azSJH5Hqv4ep7PhZLxgm/sM+vqsItx9Wnmd
Kr/MS9919S3Jbj+NB8M5xvnxtM61P0y6tst3uJ72+4bG/X9z/l+9Pv4DXd7/
6Qa1sbWdxhuP/znXqsT/doJVY9tiGrX9X6t/Y67w/9SPlPF/J/jnw8//8sFq
78Fvf7Xx640/0Hf9/xs68h9OG//+/c8//am38cHGv37+6VFdWTZ7P0ymo/TH
3727jBcUFBQUNMKhHw8zzub9W/B4b4sb/H8O0lzyBemIEuX9n06wd1I9WFId
FVPOgzU2oVQ+SAkqeKdN1IASaKiPUrsFr2aNy0Znn8hNTzlz453ywBZ1iIbf
z/BosutfzOrRPP7oD49GCIORryNM6iH95/WIcXGyaaTg+eCTUl1fJBsJW9+y
uCRsfXPskbD1LdhRl9na3v4lYU1530vC1sdLVPun+8VP/SVMyVZnw/lkOsRZ
W2nc9PsvB7ja/pNBlPa/C5ysWuia61420mv4Pej0tNhcQUFBwV3GfwHMszUX
AMIAAA==
====
EOF
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
example3 latest 059a3878de45 5 minutes ago 63B
$ python3 dedockify.py 059a3878de45
FROM example3:latest
WORKDIR /testdir1
COPY file:322f9f92e3c94eaee1dc0d23758e17b798f39aea6baec8f9594b2e4ccd03e9d0 in testfile1
WORKDIR /testdir2
COPY file:322f9f92e3c94eaee1dc0d23758e17b798f39aea6baec8f9594b2e4ccd03e9d0 in testfile2
WORKDIR /testdir3
COPY file:322f9f92e3c94eaee1dc0d23758e17b798f39aea6baec8f9594b2e4ccd03e9d0 in testfile3
WORKDIR /app
COPY file:b33b40f2c07ced0b9ba6377b37f666041d542205e0964bc26dc0440432d6e861 in hello
ENTRYPOINT ["/app/hello"]
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive:latest example3:latest
Dive screenshot by author.
이제 해당 파일을 복구하겠습니다! 이미지에서 직접 파일을 복사하는 방법이 없는 것 같으므로 먼저 컨테이너를 만들어야 합니다.
$ docker run -td example3:latest
6fdca182a128df7a76e618931c85a67e14a73adc69ad23782bc9a5dc29420a27
/testdir1/testfile1
/testdir2/testfile2
/testdir3/testfile3
/app/hello
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6fdca182a128 example3:latest "/app/hello" 2 minutes ago Up 2 minutes wizardly_lamport
$ docker container ls -a
$ docker logs 6fdca182a128
Hello, world!
docker cp 6fdca182a128:/testdir1/testfile1 .
docker cp 6fdca182a128:/testdir2/testfile2 .
docker cp 6fdca182a128:/testdir3/testfile3 .
docker cp 6fdca182a128:/app/hello .
$ ./hello
Hello, world!
FROM scratch
WORKDIR /testdir1
COPY testfile1 .
WORKDIR /testdir2
COPY testfile2 .
WORKDIR /testdir3
COPY testfile3 .
WORKDIR /app
COPY hello .
ENTRYPOINT ["/app/hello"]
먼저 컨테이너를 빌드합니다.
$ docker build . -t example3:recovered
Sending build context to Docker daemon 4.608kB
Step 1/10 : FROM scratch
--->
Step 2/10 : WORKDIR /testdir1
---> Running in 5e8e47505ca6
Removing intermediate container 5e8e47505ca6
---> d30a2f002626
Step 3/10 : COPY testfile1 .
---> 4ac46077a588
Step 4/10 : WORKDIR /testdir2
---> Running in 8c48189da985
Removing intermediate container 8c48189da985
---> 7c7d90bc2219
Step 5/10 : COPY testfile2 .
---> 5b40d33100e1
Step 6/10 : WORKDIR /testdir3
---> Running in 4ccd634a04db
Removing intermediate container 4ccd634a04db
---> f89fdda8f059
Step 7/10 : COPY testfile3 .
---> 9542f614200d
Step 8/10 : WORKDIR /app
---> Running in 7614b0fdba42
Removing intermediate container 7614b0fdba42
---> 6d686935a791
Step 9/10 : COPY hello .
---> cd4baca758dd
Step 10/10 : ENTRYPOINT ["/app/hello"]
---> Running in 28a1ca58b27f
Removing intermediate container 28a1ca58b27f
---> 35dfd9240a2e
Successfully built 35dfd9240a2e
Successfully tagged example3:recovered
$ docker run --name recovered -dt example3:recovered
0f696bf500267a996339b522cf584e010434103fe82497df2c1fa58a9c548f20
$ docker logs recovered
Hello, world!
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive:latest example3:recovered
Dive screenshot by author.
다음은 원본 이미지 Dockerfile
를 생성하는 데 사용된 원본 입니다.example3
FROM alpine:3.9.2
RUN apk add --no-cache nasm
WORKDIR /app
COPY hello.s /app/hello.s
RUN touch testfile && nasm -f bin -o hello hello.s && chmod +x hello
FROM scratch
WORKDIR /testdir1
COPY --from=0 /app/testfile testfile1
WORKDIR /testdir2
COPY --from=0 /app/testfile testfile2
WORKDIR /testdir3
COPY --from=0 /app/testfile testfile3
WORKDIR /app
COPY --from=0 /app/hello hello
ENTRYPOINT ["/app/hello"]```
미래의 일
Dive와 유사한 접근 방식을 사용하여 Dedockify 소스 코드를 업데이트하여 모든 유용한 파일 정보를 복구하기 위해 각 레이어를 자동으로 통과하도록 할 수 있어야 합니다. 또한 컨테이너에서 파일을 자동으로 복구하고 로컬에 저장할 수 있도록 프로그램을 업데이트하는 동시에 Dockerfile
. scratch
마지막으로 기본 레이어가 빈 이미지를 사용하는지 아니면 다른 것을 사용하는지 쉽게 추론할 수 있도록 프로그램을 업데이트할 수도 있습니다 . Dockerfile
복구된 구문 에 대한 몇 가지 추가 변경 사항을 통해 DedockifyDockerfile
는 잠재적으로 업데이트 되어 대부분의 경우 Docker 이미지의 리버스 엔지니어링을 기능으로 완전히 자동화할 수 있습니다 .

업데이트: 2022년 7월 11일
저는 2020년 대유행이 시작되는 동안 위의 연습을 작성하도록 위임받았고 피칭했습니다. Appfleet 에서 게시 했으며 2020년 5월 25일에 Appfleet 블로그 게시물 로 제공 되었습니다. 이 Docker Reverse Engineering 기사의 버전은 다음과 같을 수도 있습니다. 내 HavDevOps 블로그 에서 찾았습니다 . 위에서 업데이트된 스토리를 약간의 편집 및 형식 변경만으로 매체에 게시합니다. 누군가 내 주의가 필요한 오류를 발견하면 언제든지 의견을 말하십시오.
Mark Havens 는 미국에서 가장 큰 자원 봉사 메이커 스페이스인 Dallas Makerspace 를 부트스트랩하기 위해 조직된 비영리 단체인 Dallas Maker Community (DMC) 의 설립자이자 전무이사 입니다. DMC는 북텍사스 전역의 다른 메이커 중심 조직에 메이커 중심 마케팅 및 메이커스페이스 리더십 교육을 제공하기 위해 개혁적인 노력을 계속하고 있습니다.