无忧启动论坛

 找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
查看: 8118|回复: 17
打印 上一主题 下一主题

[求助] 请教P大,ISO内的文件直接访问的问题

[复制链接]
跳转到指定楼层
1#
发表于 2018-12-20 21:55:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
记得之前你的某个帖子里说过,ISO文件内的信息在头部有文件列表和文件起始值和文件长度等信息。
请问在windows下怎么把这个ISO内部文件直接"映射"出来供第三方程序直接使用?(不知道这里用映射这个词词对不对。。。)

比如ISO内的INSTALL.WIM文件,不挂载ISO而直接在Windows下第三方程序直接使用。
2#
发表于 2018-12-20 23:10:31 | 只看该作者
勋章哪来的?
回复

使用道具 举报

3#
发表于 2018-12-20 23:41:26 | 只看该作者
iso 里面的文件,全都是连续、没有碎片的。用 grub4dos 的 blocklist 命令可以列出文件的起始地址和长度。当然,这里需要先用 map 命令把 iso 映射成光驱,比如 (0xFF):

map (...)/.../.../my.iso  (0xFF)
map --hook
root (0xFF)

然后,就可以用

blocklist /.../INSTALL.WIM

来列出它的扇区序列了。注意,光驱的扇区大小是 2048 字节,不是 512 字节。

也就是说,用这种办法,你就知道 INSTALL.WIM 相对于 iso 的偏移量以及所占用的扇区总数了。

点评

我意思是在Windows下用,有方法吗?  详情 回复 发表于 2018-12-20 23:53
回复

使用道具 举报

4#
 楼主| 发表于 2018-12-20 23:53:03 来自手机 | 只看该作者
不点 发表于 2018-12-20 23:41
iso 里面的文件,全都是连续、没有碎片的。用 grub4dos 的 blocklist 命令可以列出文件的起始地址和长度。 ...

我意思是在Windows下用,有方法吗?
回复

使用道具 举报

5#
发表于 2018-12-21 00:06:57 | 只看该作者
刚才给出的,就是一个方法。当你知道了 INSTALL.WIM 的起始地址和长度以后,你就可以在任何操作系统下找到 INSTALL.WIM 的数据了。

点评

另外的方法,不是这种。  详情 回复 发表于 2018-12-21 00:47
回复

使用道具 举报

6#
 楼主| 发表于 2018-12-21 00:47:56 来自手机 | 只看该作者
不点 发表于 2018-12-21 00:06
刚才给出的,就是一个方法。当你知道了 INSTALL.WIM 的起始地址和长度以后,你就可以在任何操作系统下找到  ...

另外的方法,不是这种。
回复

使用道具 举报

7#
发表于 2018-12-21 08:12:59 | 只看该作者
就算要直接使用也需要编程进行计算,这个成品程序无疑与解压软件、虚拟软件差不多。
回复

使用道具 举报

8#
发表于 2018-12-21 09:36:05 | 只看该作者
同意各位观点,所谓直接用也还是需要进行后台处置的。
勋章倒是正常,我发现名字是五颜六色的。

点评

是哦,名字有不同颜色  详情 回复 发表于 2018-12-22 09:02
回复

使用道具 举报

9#
发表于 2018-12-22 09:02:20 | 只看该作者
窄口牛 发表于 2018-12-21 09:36
同意各位观点,所谓直接用也还是需要进行后台处置的。
勋章倒是正常,我发现名字是五颜六色的。

是哦,名字有不同颜色
回复

使用道具 举报

10#
发表于 2018-12-22 17:38:43 | 只看该作者
一个iso文件,打包了多个文件,其中有文件A,现在要获得文件A的内容,怎么办?

一种方法是先利用某工具挂载iso成为虚拟光盘,然后iso里的文件就如同磁盘上的文件,从中找文件A来读取其内容就行了。

另一种是不挂载ISO,而直接读出A的内容,这是可以办到的。
A的内容实际上占据iso内某片连续区域,这片区域从何处开始,长度多少,看iso文件的头部就可以确定。
知道了文件A在iso内的偏移和长度,那么打开(fopen)整个iso文件,指针定位(fseek)到适当的偏移,连续读取(fread)适当长度的内容就得到A的内容了。

这里直接读出A的内容,过程中并没有产生一个磁盘文件A让第三方去使用,但已经得到其内容了,可以作某些运用啦。非要一个文件A不可的话,把得到的文件内容再写出到磁盘形成文件A就是了。但这样就变成另一个问题了——怎样从iso里提取生成文件A?许多现成压缩解压工具(含命令行版本)都能直接从iso里析出其内任一文件或文件夹。

0PE提供的批处理可生成针对iso文件优化的grldr,此grldr对iso内文件是直接读取的,而不是先映射iso为虚拟光盘再从后者读取的,这样对于某些老机加快了PE启动速度。

点评

哦,看你的方法,还不是我想要实现的最终效果。 我想达到的效果,是通过ISO头文件已经确认了A文件的起始位置和长度,然后不挂载该ISO,直接通过Windows下的某个API直接映射出这个A文件出来。 感谢。 我再找找资料  详情 回复 发表于 2018-12-22 22:34
回复

使用道具 举报

11#
发表于 2018-12-22 21:37:54 | 只看该作者
我想他不是要A要B。
而是要 ABC......的方法。

点评

P大和上面的兄弟所说的都是grub4dos的环境,我说的是windows环境。。。 确实如兄弟所说,我是想直接"映射"出这个A文件出来供第三方程序直接使用。  详情 回复 发表于 2018-12-22 22:38
回复

使用道具 举报

12#
 楼主| 发表于 2018-12-22 22:34:08 | 只看该作者
本帖最后由 红毛樱木 于 2018-12-22 22:36 编辑
pseudo 发表于 2018-12-22 17:38
一个iso文件,打包了多个文件,其中有文件A,现在要获得文件A的内容,怎么办?

一种方法是先利用某工具 ...


哦,看你的方法,还不是我想要实现的最终效果。
我想达到的效果,是通过ISO头文件已经确认了A文件的起始位置和长度,然后不挂载该ISO,直接通过Windows下的某个API直接映射出这个A文件出来。
感谢。
我再找找资料研究下,暂时没找到相关API。
回复

使用道具 举报

13#
 楼主| 发表于 2018-12-22 22:38:01 | 只看该作者
vaf 发表于 2018-12-22 21:37
我想他不是要A要B。
而是要 ABC......的方法。

P大和上面的兄弟所说的都是grub4dos的环境,我说的是windows环境。。。
确实如兄弟所说,我是想直接"映射"出这个A文件出来供第三方程序直接使用。
回复

使用道具 举报

14#
发表于 2018-12-22 23:36:25 | 只看该作者
我感觉用压缩软件的命令行方式应该能操作 ISO.
回复

使用道具 举报

15#
发表于 2019-1-8 05:12:01 | 只看该作者
神奇
回复

使用道具 举报

16#
发表于 2019-1-26 03:01:08 | 只看该作者
弄了个小程序。代码如下。
  1. #include <stdio.h>
  2. #include <tchar.h>
  3. #include <locale.h>
  4. #include <tchar.h>
  5. #include <string>
  6. #include <vector>
  7. #include <mbstring.h>
  8. #include <stdlib.h>  

  9. using namespace std;
  10. #ifdef _UNICODE
  11. typedef wstring _tstring;

  12. #else
  13. typedef string _tstring;

  14. #endif



  15. #define ATAPI_SECTOR_SIZE 2048 //一个CD扇区2048Byte
  16. #define LBA_TO_BYTE(x) (x*ATAPI_SECTOR_SIZE)
  17. //用法isodr.exe <iso文件> <光盘内路径> <输出路径>
  18. //例:isodr.exe C:\abc.iso /boot/boot.sdi C:\abc.tmp
  19. //例:isodr.exe C:\abc.iso /bootmgr C:\bootmgr //输出根目录下的bootmgr
  20. //直接运行程序显示本帮助。

  21. struct FILE_ITEM{
  22.         unsigned long lba;
  23.         string FileName;
  24.         unsigned long size;
  25. };

  26. int _t_real_main(int argc, _TCHAR* argv[]);
  27. int PraseFileSystemAndFind(FILE* isofile,unsigned long lba,FILE_ITEM &item,int depth,const vector<string> &NeedFileName,bool &isfound);

  28. int _tmain(int argc, _TCHAR* argv[])
  29. {
  30.         _TCHAR *help_txt = _T("ISO文件直接读取工具\t作者:sunsea\t参考网上部分代码改编而成\n高歌酹酒,来者相候,唤我今日,长缨在手。\n\n用法isodr.exe <iso文件> <光盘内路径> <输出路径>\n例:isodr.exe C:\\abc.iso /boot/boot.sdi C:\\abc.tmp\n例:isodr.exe C:\\abc.iso /bootmgr C:\\bootmgr 输出根目录下的bootmgr\n\n直接运行程序显示本帮助。");
  31.         setlocale(LC_ALL,"chs");

  32.         if (argc==1) {
  33.                 _tprintf(help_txt);
  34.         }
  35.         if (argc>1){
  36.                 return _t_real_main(argc,argv);
  37.         }
  38.         return 0;
  39. }

  40. inline size_t seek_and_read(FILE* file,void* buf,unsigned long offest,unsigned long length){
  41.         fseek(file,offest,SEEK_SET);
  42.         return fread(buf,length,1,file);
  43. }


  44. int _t_real_main(int argc, _TCHAR* argv[]){
  45. //这里是真正做事情的代码。
  46.         //先检查源文件是否存在。
  47.         _TCHAR *source_filename=argv[1];
  48.         FILE * source_iso=NULL;
  49.         FILE_ITEM myFile;//目标文件
  50.         source_iso=_tfopen(source_filename,_T("rb"));
  51.         if (source_iso==NULL)
  52.         {
  53.                 _ftprintf(stderr,_T("源ISO镜像打开失败!请检查文件。"));
  54.                 return -1;
  55.         }
  56.         FILE *output=_tfopen(argv[3],_T("wb"));
  57.         if (output==NULL){
  58.                 _ftprintf(stderr,_T("目标文件打开失败!请检查文件。"));

  59.                 return -1;
  60.         }

  61.         char buf_sector_1[ATAPI_SECTOR_SIZE];
  62.         /* iso的前32768字节被保留,检查CD001标志*/
  63.         unsigned long lba = (0x8000 / 0x800); /*从0x8000的地方开始寻找.*/
  64.         for(;;++lba)
  65.         {
  66.                 //ISO9660最大允许整个iso 2G大小。
  67.                 if(!seek_and_read(source_iso,buf_sector_1,LBA_TO_BYTE(lba),ATAPI_SECTOR_SIZE)) { //读一个扇区
  68.                         _ftprintf(stderr,_T("源ISO镜像读取错误!请检查文件。"));
  69.                         return -1;
  70.                 }
  71.                 /*Identifier is always "CD001".*/
  72.                 if(buf_sector_1[1] != 'C' ||
  73.                         buf_sector_1[2] != 'D' ||
  74.                         buf_sector_1[3] != '0' ||
  75.                         buf_sector_1[4] != '0' ||
  76.                         buf_sector_1[5] != '1' ) /*判断CD001 不符合直接返回.*/

  77.                 {
  78.                         _ftprintf(stderr,_T("源ISO镜像非法!"));
  79.                         return -1;
  80.                 }
  81.                 if(buf_sector_1[0] == 0xff) /*Volume Descriptor Set Terminator.*/
  82.                         return -1; /*如果这是最后一个 也返回.*/
  83.                 if(buf_sector_1[0] != 0x01 /*Primary Volume Descriptor.*/)
  84.                         continue; /*不是Primary Volume Descriptor就继续*/

  85.                 /*Directory entry for the root directory.*/
  86.                 if(buf_sector_1[156] != 0x22 /*Msut 34.*/)
  87.                         return -1;

  88.                 /*Location of extent (LBA) in both-endian format.*/
  89.                 lba = *(unsigned long *)(buf_sector_1 + 156 + 2);
  90.                 break; /*读LBA,跳出.*/
  91.         }
  92.     //分析文件名。分解出目录
  93.         string Temp;
  94.         vector<string> WantedFileName;
  95.         char *token = NULL;
  96.         char *next_token = NULL;
  97.         char *Wanted;
  98.         bool isfound=false;

  99. #ifdef _UNICODE
  100.         int need=0;
  101.         need=wcstombs(NULL,argv[2],0)+1;
  102.         Wanted = new char[need];
  103.         wcstombs(Wanted,argv[2],need);
  104. #else
  105.         Wanted = new char[strlen(argv[1])+1];
  106.         strcpy(Wanted,argv[1]);
  107. #endif
  108.         token=strtok_s(Wanted,"/",&next_token);
  109.         
  110.         while (token != NULL)
  111.         {
  112.                 if (token != NULL)
  113.                 {
  114.                         Temp=token;
  115.                         WantedFileName.push_back(Temp);
  116.                         token = strtok_s(NULL,"/", &next_token);
  117.                         
  118.                 }
  119.         }

  120.         delete [] Wanted;//切分完毕
  121.         PraseFileSystemAndFind(source_iso,lba,myFile,0,WantedFileName,isfound);
  122.         if (!isfound){
  123.                 _ftprintf(stderr,_T("没找到你要的文件!"));
  124.         }else{
  125.                 _tprintf(_T("找到目标文件,大小%d,LBA %d\n"),myFile.size,myFile.lba);
  126.                 fseek(source_iso,LBA_TO_BYTE(myFile.lba),SEEK_SET);
  127.                 char buffer[4096]; //按4K一块
  128.                 for (unsigned int i=0;i<=(myFile.size/4096);i++){
  129.                         if (i==(myFile.size/4096)){
  130.                                 //最后一块
  131.                                 fread(buffer,myFile.size-i*4096,1,source_iso);
  132.                                 fwrite(buffer,myFile.size-i*4096,1,output);
  133.                                 _tprintf(_T("输出完毕。"));
  134.                         }else{
  135.                                 fread(buffer,4096,1,source_iso);
  136.                                 fwrite(buffer,4096,1,output);
  137.                         }
  138.                 }
  139.         }
  140.         fclose(output);
  141.         fclose(source_iso);
  142.         if (!isfound){
  143.                 _tremove(argv[3]);
  144.         }
  145.         
  146.         return 0;
  147. }

  148. int PraseFileSystemAndFind(FILE* isofile,unsigned long lba,FILE_ITEM &item,int depth,const vector<string> &NeedFileName,bool &isfound){
  149.         
  150. isfound=false;


  151.         char SectorBuf[ATAPI_SECTOR_SIZE];
  152.         seek_and_read(isofile,SectorBuf,LBA_TO_BYTE(lba),ATAPI_SECTOR_SIZE);

  153.    unsigned long offset = 0; /*要读的文件(夹)的信息结构的偏移.*/
  154.    bool isDir = 0; /*是否是文件夹.*/
  155.    bool needRead = 0; /*需不需要重新读.*/

  156.    for(;;offset += SectorBuf[offset + 0x0] /*Length of Directory Record.*/)
  157.    {
  158.       while(offset >= ATAPI_SECTOR_SIZE)
  159.       {
  160.          offset -= ATAPI_SECTOR_SIZE;
  161.          ++lba;
  162.          needRead = 1;
  163.          /*Read again.*/
  164.       } /*偏移超出这个扇区的范围就修正一下.*/
  165.       if(needRead)
  166.         seek_and_read(isofile,SectorBuf,LBA_TO_BYTE(lba),ATAPI_SECTOR_SIZE);
  167.       needRead = 0;
  168.       
  169.       if(SectorBuf[offset + 0x0] == 0x0) /*No more.*/
  170.          break; /*大小是0说明结束了,退出.*/
  171.       
  172.       /*Location of extent (LBA) in both-endian format.*/
  173.       unsigned long fileLBA = *(unsigned long *)(SectorBuf + offset + 0x2);
  174.       if(fileLBA <= lba)
  175.         continue; /*获取文件LBA,小于就继续吧.*/


  176.       isDir = SectorBuf[offset + 25] & 0x2; /*Is it a dir?*/

  177.       unsigned long filesize = *(unsigned long *)(SectorBuf + offset + 10);

  178.       /*Length of file identifier (file name).
  179.        * This terminates with a ';' character
  180.        * followed by the file ID number in ASCII coded decimal ('1').*/
  181.       unsigned long filenameLength = SectorBuf[offset + 32];
  182.       //if(!isDir) /*如果是文件就要删掉最后的";1".*/
  183.       //   filenameLength -= 2; /*Remove ';' and '1'.*/

  184.       char *filename =new char[filenameLength + 1]; /*Add 1 for '\0'.*/
  185.       memcpy(filename,
  186.          (const void *)(SectorBuf + offset + 33),
  187.          filenameLength); /*把文件名复制过来.*/

  188.       if((!isDir) && (filename[0] == '_'))
  189.          filename[0] = '.';
  190.       if((!isDir) && (filename[filenameLength - 1] == '.'))
  191.          filename[filenameLength - 1] = '\0';
  192.       else
  193.          filename[filenameLength] = '\0'; /*做一些修正.*/

  194.       string _filename_safe = filename;
  195. delete [] filename;

  196.       if(!isDir)
  197.       {

  198.                   if(filesize != 0)
  199.                   {
  200.                           if (!stricmp(NeedFileName[depth].c_str(),_filename_safe.c_str())) //找到了!
  201.                           {
  202.                                   item.FileName=_filename_safe;
  203.                                   item.lba=fileLBA;
  204.                                   item.size=filesize;
  205.                                   isfound=true;
  206.                                   return 1;
  207.                           }
  208.                   }

  209.       }
  210.       else
  211.       {
  212.                   if (!stricmp(NeedFileName[depth].c_str(),_filename_safe.c_str()))
  213.                         PraseFileSystemAndFind(isofile,fileLBA,item,depth+1,NeedFileName,isfound); /*对的就递归.*/

  214.       }
  215.    }
  216.          

  217.           return 0;
  218. }
复制代码
可以直接提取iso中文件,要求是ISO9660格式。
注意,输出的LBA是2048字节大扇区式的LBA。
如果只需要LBA和长度的话,还可以再改。

VC2005编译并测试通过。


用静态库编译,应该到哪都可以用了。

release.rar

49.89 KB, 下载次数: 18, 下载积分: 无忧币 -2

回复

使用道具 举报

17#
发表于 2019-1-27 09:42:58 来自手机 | 只看该作者
这是要在win下loopback么
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1 )

闽公网安备 35020302032614号

GMT+8, 2024-11-24 00:37

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表