千家信息网

Docker镜像的逆向工程怎么实现

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章主要讲解了"Docker镜像的逆向工程怎么实现",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Docker镜像的逆向工程怎么实现"吧!首先,让
千家信息网最后更新 2026年11月02日Docker镜像的逆向工程怎么实现

这篇文章主要讲解了"Docker镜像的逆向工程怎么实现",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Docker镜像的逆向工程怎么实现"吧!

首先,让 Docker 守护进程daemon拉取镜像,然后将镜像提取到文件中:

docker pull tmknom/prettier:2.0.5docker save tmknom/prettier:2.0.5 > prettier.tar

是的,该文件只是一个典型 tarball 格式的归档文件:

$ tar xvf prettier.tar6c37da2ee7de579a0bf5495df32ba3e7807b0a42e2a02779206d165f55f1ba70/6c37da2ee7de579a0bf5495df32ba3e7807b0a42e2a02779206d165f55f1ba70/VERSION6c37da2ee7de579a0bf5495df32ba3e7807b0a42e2a02779206d165f55f1ba70/json6c37da2ee7de579a0bf5495df32ba3e7807b0a42e2a02779206d165f55f1ba70/layer.tar88f38be28f05f38dba94ce0c1328ebe2b963b65848ab96594f8172a9c3b0f25b.jsona9cc4ace48cd792ef888ade20810f82f6c24aaf2436f30337a2a712cd054dc97/a9cc4ace48cd792ef888ade20810f82f6c24aaf2436f30337a2a712cd054dc97/VERSIONa9cc4ace48cd792ef888ade20810f82f6c24aaf2436f30337a2a712cd054dc97/jsona9cc4ace48cd792ef888ade20810f82f6c24aaf2436f30337a2a712cd054dc97/layer.tard4f612de5397f1fc91272cfbad245b89eac8fa4ad9f0fc10a40ffbb54a356cb4/d4f612de5397f1fc91272cfbad245b89eac8fa4ad9f0fc10a40ffbb54a356cb4/VERSIONd4f612de5397f1fc91272cfbad245b89eac8fa4ad9f0fc10a40ffbb54a356cb4/jsond4f612de5397f1fc91272cfbad245b89eac8fa4ad9f0fc10a40ffbb54a356cb4/layer.tarmanifest.jsonrepositories

如你所见,Docker 在命名时经常使用哈希hash。我们看看 manifest.json。它是以难以阅读的压缩 JSON 写的,不过 JSON 瑞士军刀 jq 可以很好地打印 JSON:

$ jq . manifest.json[  {    "Config": "88f38be28f05f38dba94ce0c1328ebe2b963b65848ab96594f8172a9c3b0f25b.json",    "RepoTags": [      "tmknom/prettier:2.0.5"    ],    "Layers": [      "a9cc4ace48cd792ef888ade20810f82f6c24aaf2436f30337a2a712cd054dc97/layer.tar",      "d4f612de5397f1fc91272cfbad245b89eac8fa4ad9f0fc10a40ffbb54a356cb4/layer.tar",      "6c37da2ee7de579a0bf5495df32ba3e7807b0a42e2a02779206d165f55f1ba70/layer.tar"    ]  }]

请注意,这三个层Layer对应三个以哈希命名的目录。我们以后再看。现在,让我们看看 Config 键指向的 JSON 文件。它有点长,所以我只在这里转储第一部分:

$ jq . 88f38be28f05f38dba94ce0c1328ebe2b963b65848ab96594f8172a9c3b0f25b.json | head -n 20{  "architecture": "amd64",  "config": {    "Hostname": "",    "Domainname": "",    "User": "",    "AttachStdin": false,    "AttachStdout": false,    "AttachStderr": false,    "Tty": false,    "OpenStdin": false,    "StdinOnce": false,    "Env": [      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"    ],    "Cmd": [      "--help"    ],    "ArgsEscaped": true,    "Image": "sha256:93e72874b338c1e0734025e1d8ebe259d4f16265dc2840f88c4c754e1c01ba0a",

最重要的是 history 列表,它列出了镜像中的每一层。Docker 镜像由这些层堆叠而成。Dockerfile 中几乎每条命令都会变成一个层,描述该命令对镜像所做的更改。如果你执行 RUN script.sh 命令创建了 really_big_file,然后用 RUN rm really_big_file 命令删除文件,Docker 镜像实际生成两层:一个包含 really_big_file,一个包含 .wh.really_big_file 记录来删除它。整个镜像文件大小不变。这就是为什么你会经常看到像 RUN script.sh && rm really_big_file 这样的 Dockerfile 命令链接在一起——它保障所有更改都合并到一层中。

以下是该 Docker 镜像中记录的所有层。注意,大多数层不改变文件系统镜像,并且 empty_layer 标记为 true。以下只有三个层是非空的,与我们之前描述的相符。

$ jq .history 88f38be28f05f38dba94ce0c1328ebe2b963b65848ab96594f8172a9c3b0f25b.json[  {    "created": "2020-04-24T01:05:03.608058404Z",    "created_by": "/bin/sh -c #(nop) ADD file:b91adb67b670d3a6ff9463e48b7def903ed516be66fc4282d22c53e41512be49 in / "  },  {    "created": "2020-04-24T01:05:03.92860976Z",    "created_by": "/bin/sh -c #(nop)  CMD [\"/bin/sh\"]",    "empty_layer": true  },  {    "created": "2020-04-29T06:34:06.617130538Z",    "created_by": "/bin/sh -c #(nop)  ARG BUILD_DATE",    "empty_layer": true  },  {    "created": "2020-04-29T06:34:07.020521808Z",    "created_by": "/bin/sh -c #(nop)  ARG VCS_REF",    "empty_layer": true  },  {    "created": "2020-04-29T06:34:07.36915054Z",    "created_by": "/bin/sh -c #(nop)  ARG VERSION",    "empty_layer": true  },  {    "created": "2020-04-29T06:34:07.708820086Z",    "created_by": "/bin/sh -c #(nop)  ARG REPO_NAME",    "empty_layer": true  },  {    "created": "2020-04-29T06:34:08.06429638Z",    "created_by": "/bin/sh -c #(nop)  LABEL org.label-schema.vendor=tmknom org.label-schema.name=tmknom/prettier org.label-schema.description=Prettier is an opinionated code formatter. org.label-schema.build-date=2020-04-29T06:34:01Z org.label-schema.version=2.0.5 org.label-schema.vcs-ref=35d2587 org.label-schema.vcs-url=https://github.com/tmknom/prettier org.label-schema.usage=https://github.com/tmknom/prettier/blob/master/README.md#usage org.label-schema.docker.cmd=docker run --rm -v $PWD:/work tmknom/prettier --parser=markdown --write '**/*.md' org.label-schema.schema-version=1.0",    "empty_layer": true  },  {    "created": "2020-04-29T06:34:08.511269907Z",    "created_by": "/bin/sh -c #(nop)  ARG NODEJS_VERSION=12.15.0-r1",    "empty_layer": true  },  {    "created": "2020-04-29T06:34:08.775876657Z",    "created_by": "/bin/sh -c #(nop)  ARG PRETTIER_VERSION",    "empty_layer": true  },  {    "created": "2020-04-29T06:34:26.399622951Z",    "created_by": "|6 BUILD_DATE=2020-04-29T06:34:01Z NODEJS_VERSION=12.15.0-r1 PRETTIER_VERSION=2.0.5 REPO_NAME=tmknom/prettier VCS_REF=35d2587 VERSION=2.0.5 /bin/sh -c set -x &&     apk add --no-cache nodejs=${NODEJS_VERSION} nodejs-npm=${NODEJS_VERSION} &&     npm install -g prettier@${PRETTIER_VERSION} &&     npm cache clean --force &&     apk del nodejs-npm"  },  {    "created": "2020-04-29T06:34:26.764034848Z",    "created_by": "/bin/sh -c #(nop) WORKDIR /work"  },  {    "created": "2020-04-29T06:34:27.092671047Z",    "created_by": "/bin/sh -c #(nop)  ENTRYPOINT [\"/usr/bin/prettier\"]",    "empty_layer": true  },  {    "created": "2020-04-29T06:34:27.406606712Z",    "created_by": "/bin/sh -c #(nop)  CMD [\"--help\"]",    "empty_layer": true  }]

太棒了!所有的命令都在 created_by 字段中,我们几乎可以用这些命令重建 Dockerfile。但不是完全可以。最上面的 ADD 命令实际上没有给我们需要添加的文件。COPY 命令也没有全部信息。我们还失去了 FROM 语句,因为它们扩展成了从基础 Docker 镜像继承的所有层。

我们可以通过查看时间戳timestamp,按 Dockerfile 对层进行分组。大多数层的时间戳相差不到一分钟,代表每一层构建所需的时间。但是前两层是 2020-04-24,其余的是 2020-04-29。这是因为前两层来自一个基础 Docker 镜像。理想情况下,我们可以找出一个 FROM 命令来获得这个镜像,这样我们就有了一个可维护的 Dockerfile。

manifest.json 展示第一个非空层是 a9cc4ace48cd792ef888ade20810f82f6c24aaf2436f30337a2a712cd054dc97/layer.tar。让我们看看它:

$ cd a9cc4ace48cd792ef888ade20810f82f6c24aaf2436f30337a2a712cd054dc97/$ tar tf layer.tf | headbin/bin/archbin/ashbin/base64bin/bbconfigbin/busyboxbin/catbin/chgrpbin/chmodbin/chown

看起来它可能是一个操作系统operating system基础镜像,这也是你期望从典型 Dockerfile 中看到的。Tarball 中有 488 个条目,如果你浏览一下,就会发现一些有趣的条目:

...dev/etc/etc/alpine-releaseetc/apk/etc/apk/archetc/apk/keys/etc/apk/keys/alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pubetc/apk/keys/alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pubetc/apk/keys/alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pubetc/apk/protected_paths.d/etc/apk/repositoriesetc/apk/worldetc/conf.d/...

果不其然,这是一个 Alpine 镜像,如果你注意到其他层使用 apk 命令安装软件包,你可能已经猜到了。让我们解压 tarball 看看:

$ mkdir files$ cd files$ tar xf ../layer.tar$ lsbin  dev  etc  home  lib  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var$ cat etc/alpine-release3.11.6

如果你拉取、解压 alpine:3.11.6,你会发现里面有一个非空层,layer.tar 与 Prettier 镜像基础层中的 layer.tar 是一样的。

出于兴趣,另外两个非空层是什么?第二层是包含 Prettier 安装包的主层。它有 528 个条目,包含 Prettier、一堆依赖项和证书更新:

...usr/lib/libuv.so.1usr/lib/libuv.so.1.0.0usr/lib/node_modules/usr/lib/node_modules/prettier/usr/lib/node_modules/prettier/LICENSEusr/lib/node_modules/prettier/README.mdusr/lib/node_modules/prettier/bin-prettier.jsusr/lib/node_modules/prettier/doc.jsusr/lib/node_modules/prettier/index.jsusr/lib/node_modules/prettier/package.jsonusr/lib/node_modules/prettier/parser-angular.jsusr/lib/node_modules/prettier/parser-babel.jsusr/lib/node_modules/prettier/parser-flow.jsusr/lib/node_modules/prettier/parser-glimmer.jsusr/lib/node_modules/prettier/parser-graphql.jsusr/lib/node_modules/prettier/parser-html.jsusr/lib/node_modules/prettier/parser-markdown.jsusr/lib/node_modules/prettier/parser-postcss.jsusr/lib/node_modules/prettier/parser-typescript.jsusr/lib/node_modules/prettier/parser-yaml.jsusr/lib/node_modules/prettier/standalone.jsusr/lib/node_modules/prettier/third-party.jsusr/local/usr/local/share/usr/local/share/ca-certificates/usr/sbin/usr/sbin/update-ca-certificatesusr/share/usr/share/ca-certificates/usr/share/ca-certificates/mozilla/usr/share/ca-certificates/mozilla/ACCVRAIZ1.crtusr/share/ca-certificates/mozilla/AC_RAIZ_FNMT-RCM.crtusr/share/ca-certificates/mozilla/Actalis_Authentication_Root_CA.crt...

第三层由 WORKDIR /work 命令创建,它只包含一个条目:

$ tar tf 6c37da2ee7de579a0bf5495df32ba3e7807b0a42e2a02779206d165f55f1ba70/layer.tarwork/

原始 Dockerfile 在 Prettier 的 git 仓库中。

感谢各位的阅读,以上就是"Docker镜像的逆向工程怎么实现"的内容了,经过本文的学习后,相信大家对Docker镜像的逆向工程怎么实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

镜像 命令 文件 工程 逆向工程 基础 条目 三个 时间 学习 典型 内容 实际 就是 情况 系统 这是 哈希 原始 有趣 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网与科技 广州大一互联网络科技有限公司 互联网科技产业 互联网科技有限公司经营范围 新华互联网科技学院 云电互联网科技 丰台科技园 互联网 甘肃拓世互联网科技有限公司 上海电发互联网科技有限公司 科技赋能互联网健康 青岛中康互联网医疗科技有限公司 哈尔滨新华互联网科技学院 宜昌元轩互联网科技有限公司 互联网科技的全部知识 阿里互联网科技企业 互联网金融科技名词解释 沐思想互联网科技有限公司 智帮互联网科技公司最近动向 江苏互联网智能科技软件 互联网科技企业商标注意事项 互联网科技社 碳银互联网科技有限公司 互联网科技生活的内容 深圳互联网科技怎么样 互联网还是高科技吗 互联网科技的全部知识 威龙国际互联网科技公司 上海创道互联网络科技有限公司 互联网时代高科技布局 株洲百竞科技的互联网营销顾问
0