今天使用的主机上有个朋友发来消息,api用不了了。贝壳检查了一下,主机正常阿。
Tag Archives: API
实践NTFS格式解析
00012580 2E 00 70 00 70 00 74 00 80 00 00 00 48 00 00 00 ..p.p.t.Ђ...H... 00012590 01 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 ................ 000125A0 6D 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 m.......@....... 000125B0 00 DC 00 00 00 00 00 00 00 DC 00 00 00 00 00 00 .U.......U...... 000125C0 00 DC 00 00 00 00 00 00 31 6E EB C4 04 00 00 00 .U......1neA.... 000125D0 FF FF FF FF 82 79 47 11 00 00 00 00 00 00 00 00 yyyy‚yG.........
Data Runs need to be decrypted. First byte (0×31) shows how many bytes are allocated for the length of the run (0×1 in our case) and for the first cluster offset (0×3 in our case). Next, we take one byte (0x6E) that points to the length of the run. Next, we pick up 3 bytes pointing to the start cluster offset (0xEBC404). Changing bytes order we get first cluster of the file 312555 (equals 0x04C4EB). Starting from this cluster we need to pick up 110 clusters (equals 0x6E).
Next byte (0×00) tells us that no more data runs exist. Our file is not fragmented, so we have the only one data run.
按照上面的说法,这个映射对也是一个链表。而且是一个非定项长非定长的链表,Null-trim的。每个段的起始一字节分成高低两个区域,高四位记录了多少字节用于记录LCN,低字节记录了多少字节用于记录运行长度。后面跟了不定长的运行长度和LCN(注意先是运行长度)。如果举$Boot的$DATA的例子来说,数值上就是11 02 00 00。描述了分区的头两个扇区,也就是Boot区,BPB表的位置。这样安排,可以使得整个分区全部规划在16个主要MFT的树型属性下面。世界完美了……
利用API插接替换破解软件
刚刚在看软件破解教程,看到一个人说怎么怎么破解软件。然后突然想到,许多软件破解其实不用修改出flag或者找注册算法。只要对话框不出来,软件照常好用就可以了。OK,基于这个原理,试试用DLL注入插接API的方法RIP破解软件。
首先是对话框弹出机理。先写了个MFC程序,然后跑一跑,在运行中按着DoModel()一路F11下去,跟进了CWnd::CreateDialogIndirectPreamA云云的一个函数里面(名字忘记了)。然后就是一个API调用了。(__IMP__Creat…肯定是调用别的DLL的函数了)API内容看不到……我晕。编译一个Release版的出来,然后上Ollydbg。经过跟踪,确定了窗体句柄是在USER32.CreateDialogIndirectPreamAorW里面生成的。如果没有窗体句柄呢?
貌似有两种可能,一种是没事,对话框没了。一种是报错。按照试验,Readbook至少是没事情的。哈哈,这样简单多了。整理下顺序,基本就可以做RIP破解了。
首先是用OllyDbg等等软件定位USER32.CreateDialogIndirectPreamAorW(其实USER32.CreateDialogIndirectPreamA更好,如果只用这个的话比较好确定参数类型)。然后下断点,跑到软件里面触发窗口广告……然后记录对话框的模板位置,调试的任务就结束了。因为没有啥要判断的东西,这个应该说简单到顶点了。
然后写一个DLL注入程序,运行目标程序并且Suspend。然后注入DLL,挂接API。详细参看windows核心编程,现在我们假定挂接了USER32.CreateDialogIndirectPreamA。现在有了一个自主的处理函数,只要在里面判断模板是否为特定模板就好……这个是module的一个res,理论上不是动态生成的,所以位置不变。而且一个对话框一个模板,很好认不会出错。如果是特定模板就返回NULL,否则正常调用。这样程序的提示框就永远弹不出来了。
这个其实是将软件的对话框禁止技术搬到了API层去实现,由于API层代码相对稳定,通用性强,所以破解相对简单。不过也是有代价的。如果软件无法生成对话框会导致出错……这个就没戏了。而且要写注入程序(可以写个注入的模板,或者一次写好可以多次用……),毕竟不是直接运行程序,使用不大方便。而且速度会受影响,如果程序里面对话框满天飞的话……
光盘镜像Copy、底层文件读写和CreateFile
1.CreateFile读写文件,设备,网络。
刚刚看到有人在问,知道了数据的物理位置,如何读取光盘上的数据。于是我很纳闷,这有何难。看他的意思不会是要编程进行硬件交互读取吧。如果已知数据的偏移地址,那么使用CreateFile(“\\.\X:”…)就可以直接读取某个盘上的数据了。(Windows 2000 Support Tools中DiskProbe就是用这种方法直接读写物理磁盘的,包括可以读写0面0道0扇区,不过他用的对象是\\.\PHYSICALDRIVEx而已)
还有可以打开的对象包括管道(会用的人一定知道),文件(废话),Consoles(简单来说就是命令行界面),通信资源(例如COM1)。据说还可以打开内存,似乎是PHYSICMEM资源,记不得了。
以上资源的打开都有限制的,多数都比较简单,就是在打开时候使用OPEN_EXISTING标志。另外还有些当然的限制,例如光盘不能做为GENERIC_WRITE打开(我是没有试过啦,不过想也知道,光盘哪里能写。)
举例来说,这次我做的ISO镜像制作程序(ISO可以是光盘的按字节镜像),代码大致就是这样的。(以下代码都是伪代码,不要拿去编译哦。)
GetLogicalDriveStrings(nBufferLength, lpBuffer);
lpRootPathName=lpBuffer;
while( lpRootPathName[0] ){
if( GetDriveType(lpRootPathName) & DRIVE_CDROM )
break;
lpRootPathName+=strlen(lpRootPathName)+1;
};
if( !lpRootPathName[0] )
return -1;
strcpy(RootPathName, “\\.\“);
strcat(RootPathName, lpRootPathName);
RootPathName[strlen(RootPathName)-1]=0;
hFileCDROM=CreateFile(RootPathName, GENERIC_READ,//我要做镜像,不是刻盘(不知道能不能刻)
FILE_SHARE_READ, NULL, //你这个用户有访问能力就是NULL,没有自己去看API编程去
OPEN_EXISTING, //必须如此,这个是打开光盘的限制条件
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //交叠模式
0);
hFileISO=CreateFile(ISOpath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
Overlap.hEvent=CreateEvent(NULL, FALSE, FALSE, NULL);
do{
Overlap.Offset=…;
Overlap.OffsetHigh=…;
ReadFile(hFileCDROM, lpBuffer, BUFF_SIZE, &NumberOfBytes, &Overlap);
WaitForSingleObject(olRead.hEvent, TimeOut);
if( !GetOverlappedResult(hFileCDROM, &Overlap, &NumberOfBytes, FALSE) ){
switch( GetLastError() ){
case ERROR_IO_INCOMPLETE:
CancelIo(hFileCDROM);
break;
default:
break;
}
//error
}
WriteFile(hFileISO, lpBuffer, BUFF_SIZE, &NumberOfBytes, NULL);
}while( 1 );
CloseHandle(Overlap.hEvent);
CloseHandle(hFileISO);
CloseHandle(hFileCDROM);
…
2.OVERLAPPED模式和大文件
上面用到一个模式,OVERLAPPED。因为我做的镜像是DVD镜像。大小超过了2G。一般操作的时候是用SetFilePointerEx或者使用OverLapped模式。前者据说在windows.h中引入了,但是我没有看到,还要自己定义。
extern “C”{
BOOL
WINAPI
SetFilePointerEx(
HANDLE hFile, // handle to file
LARGE_INTEGER liDistanceToMove, // bytes to move pointer
PLARGE_INTEGER lpNewFilePointer, // new file pointer
DWORD dwMoveMethod // starting point
);
}
加上要控制镜像的时候超时(万一读不出来)。所以采用了OVERLAPPED模式。这个模式大致意思就是说读写的时候多传递一个结构进去。里面两个有用的东西一个读写的当前位置,一个是一个由CreateEvent创建的句柄。然后就可以按照异步模式操作。不过他的条件还蛮奇怪的,我按照MSDN翻译如下。
打开文件时使用FILE_FLAG_OVERLAPPED,lpOverlapped是NULL,读写的时候立即返回,结果是Failed。
打开文件时使用FILE_FLAG_OVERLAPPED,lpOverlapped正常,读写的时候异步读写,结果等到读写完成后用GetOverlappedResult读取(当然,也有timeout的处理方法)。
打开文件时未FILE_FLAG_OVERLAPPED,lpOverlapped是NULL,读写的时候同步读写,阻塞到结果返回的时候。
然后就是最奇怪的,未FILE_FLAG_OVERLAPPED,lpOverlapped有效。NT内核下是使用了OVERLAPPED结构里面的offset,同步读写(?!)。win9X则直接报错。看来这种情况还是不要出现为妙。
3.数据泵思想
大家刚刚看了上面的代码,然后请稍微去google上找找关于如何远程操作CMD的方法。一般来说,都是使用管道将远程的指令发送给CMD.exe直接处理的。(代码在网络上已经满天飞,恕我不凑热闹了。)这里就涉及一个一样的问题。如何从一个文件对象中读取数据写到另一个文件对象中。
理论上,可以构造一个段代码专门从某个句柄COPY数据到另外一个句柄,如同windows消息泵一样的工作。但是这就面临两相关的两个问题,是否是OVERLAPPED模式打开的文件,以及文件对象的特性(例如是否需要等待等等)。根据OVERLAPPED的说明,前者可以通过全部使用OVERLAPPED减轻。(而非完全避免,请看我所说的奇怪特性。)而后者基本很难做出完美的处理。因此最多可以做一些用于通用情况的消息泵,对每种通用情况分别使用。大致可能的应用例如管道和网络间通讯(后门程序)。
另外就是代码的优化,如果读写在不同的快速对象上进行(例如两个硬盘)。那么先读后写的话,效率只有同步读写的一半。我在代码中采取的是大规模缓冲池和顺序平衡优化的方法。加上代码优化后,Copy的速度已经和Windows一样了(Windows有点投机行为,测不准)。不过CPU耗用偏高而已,这个也是没有办法啦。有兴趣的可以问我要这个程序来玩玩(代码就不用要了,这个程序蛮大的,提取读ISO的代码来也蛮困难的)。