2011年12月10日星期六

一部分老Windows Beta版本的时限炸弹破解方法

如何安装:先用启动盘把主机或者虚拟机的日期改为该beta发行日或之前(该beta的日期得查看里面文件的最老修改时间,微软的安装文件时间一般是统一的),否则很有可能无法安装成功。
破解时限炸弹:
一部分Windows版本的早期测试版没有时限炸弹(比如NT4的Build 1234),这个措施是从Chicago 三位数版本才开始出现的。
Chicago后期系:用Windows 95第一版(不支持FAT32)的启动软盘启动,sys c:。
OSR2的beta如Nashville 999之类:用第一版还是OSR2的启动盘来试,只要sys命令不报错,应该OK
Memphis系:用Win95 OSR2的启动盘,如上做。(貌似不能用Windows 98第一版的启动盘)
Millienium系:用WinME的启动盘去sys。
对于以上Win9x的Beta,还可以用一个timecrk.exe程序,在时间日期改回正确的之前跑一下,破解IO.SYS。(感谢betaarchive的giantsleen)

早于Whistler的各种NT系统(包括Neptune 5xxx):使用TweakNT.exe程序。
Whistler、Whistler Server和4074之前的Longhorn除了NT注册表里的时限炸弹,还有Windows激活的时限炸弹。需要同时使用TweakNT和AntiWPA(AntiWPA也可以用于非OEM和VOL版的XP/2003激活)才能破解。
高版本Longhorn/Vista/Server 2008,Windows 7,Windows 8的Beta版破时间炸弹方法我还不知道。
以上提到的三个工具我打了包。
http://www.mediafire.com/file/ofe4k3aq0tu6hse/timebomb.rar

2011年10月7日星期五

rundll32是如何工作的?

rundll/rundll32是和Windows 95一起出现的一个小工具。因为此工具的文档在Windows任何一版中都不存在,仅仅是微软知识库中的一篇不起眼的文章(后面会提到)而已,因此很多人只知道它可以调用任意DLL中的函数。很多所谓Windows 9x的“秘籍”,也是由运行这个去直接调用一些未公开的API函数来触发的。
不过很少有人知道这个工具所能调用的导出函数是有固定的原型的。这个发现来自我无聊的一个小实验:
rundll32 user32.dll,MessageBoxA yksoft1
结果是
所有用过Win32编程的都知道MessageBoxA的原型是
int WINAPI MessageBoxA(
HWND hWnd,
LPSTR lpText,
LPSTR lpCaption,
UINT uType
);

看看这个图,lpText看上去像一个exe或者PE文件文件头部的几个字节,lpCaption是rundll32的第二个参数,而消息框类型是MB_OKCANCEL也就是1。
最大的问题是lpText为何把某个exe的头部所在的地址传了进来,这肯定涉及到rundll32中调用函数原型的问题了。
在上网搜索之前,我先拿出个法宝来看看。2004年,微软的一家做跨平台解决方案的承包商Mainsoft遭到入侵,导致大量Windows NT4和2000系统的源码文件被泄露。这个法宝其实就是当年0day里的这个源码包了,有洋大人(ReactOS那帮人)因为这个惹上麻烦,我却不怕。
找到/private/windows/shell/rundll32/rundll.c,咱们来看看。
有一个很重要的宏,这应当就是rundll32所调用的函数原型了。
RUNDLLPROC g_lpfnCommand;
它之后这样被调用:
g_lpfnCommand(g_hwndStub, hInstance, pchCmdLine, nCmdShow);
这个宏应该在DDK的某个文件里有,但是找遍了都没找到。倒是继续翻,在这个源码包的/private/windows/inc16/shsemip.h中找到了这个宏定义。
typedef void (WINAPI FAR* RUNDLLPROCA)(HWND hwndStub,
HINSTANCE hAppInstance,
LPSTR lpszCmdLine, int nCmdShow);

typedef void (WINAPI FAR* RUNDLLPROCW)(HWND hwndStub,
HINSTANCE hAppInstance,
LPWSTR lpszCmdLine, int nCmdShow);

这是一个无返回值的stdcall类型函数,有4个参数。它们到底干什么的,还得继续看rundll.c逻辑。
int PASCAL WinMainT (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpszCmdLine, int nCmdShow)
这里是rundll32的WinMain,传进了当前基地址,上个实例的基地址,命令行参数,窗口显示方式(最大化什么的)。
if (!ParseCommand(lpszCmdLine, nCmdShow))
解析输入命令行。跟进去,里面其实包括了关键的对目标DLL进行LoadLibrary、GetProcAddress,把得到的函数地址赋给g_lpfnCommand,还有一些判断比如16位rundll调32位DLL、根据程序的ANSI/Unicode版本自动给函数名加W后缀/A后缀之类的特殊操作。最后,把传入的lpszCmdline的dll名/函数名去掉,只留下第二个参数。
if (!InitStubWindow(hInstance, hPrevInstance))
建立空窗口。其实就是一普通的RegisterClass/CreateWindowEx,不过建立了一个WS_EX_TOOLWINDOW风格的,大小0x0,这样用alt+tab之类就选不到,看上去也不可见,只能用spy++之类的工具看到。这个窗口句柄赋给g_hwndStub。
pchCmdLine = lpszCmdLine;
后面是个把pchCmdLine的Unicode字符串转ANSI的逻辑,和主逻辑关系不大,不说了。不过有个问题,根据ParseCommand里的逻辑,只有自动尝试在函数名后加W,GetProcAddress成功的函数才会被认为是Unicode的函数,如果尝试在名字后加W,加A都GetProcAddress失败,最后直接加载名字的函数就认为是ANSI函数了。这个的影响后面还要说。
try
{
g_lpfnCommand(g_hwndStub, hInstance, pchCmdLine, nCmdShow);
}
_except (EXCEPTION_EXECUTE_HANDLER)
{
RunDllErrMsg(NULL, IDS_LOADERR+17, c_szLocalizeMe, lpszCmdLine, NULL);
}
终于到最后的调用了。根据前面的说明,这些都很清楚了:g_hwndStub是建立那个空窗口的句柄,hInstance是当前rundll32.exe进程在内存中的基地址,pchCmdLine是进行所有操作后最后留下来的第二个命令行参数,nCmdShow是rundll32被启动时系统传入的窗口显示方式。
把我们最初的命令行
rundll32 user32.dll,MessageBoxA yksoft1
放进来看,经过所有操作,最后MessageBoxA会这么被调用:
MessageBoxA(g_hwndStub, hInstance, "yksoft1", nCmdShow);
对比最开始MessageBoxA的原型,第一个参数类型倒对上了,而第二个参数实际上把rundll32进程的基地址强制转换成了LPSTR也就是char*,而Windows虚地址空间中一个进程的基地址后首先是整个PE文件的映像,一开始的几个字节必定是EXE文件头"MZ"之类的,后面过一段通常会出现'\0',因此消息框内容就变成"MZ?"了。第三个参数没什么好说,而为何第四个参数会是MB_OKCANCEL,其实也就是因为系统默认的窗口显示方式是SW_SHOWNORMAL,MB_OKCANCEL==SW_SHOWNORMAL而已。
rundll32这个工具看上去并不是用来公开使用的(要不怎么连个/?参数都没有),但是为了微软长期以来纠结的向下兼容性,直到最新的Windows Developer Preview,仍然保留在系统中。也许正因为这个,这工具的使用其实非常受限制。首先是参数问题,如果rundll32误调用了cdecl传参方式的函数,由于cdecl方式是调用者而不是被调用者对参数栈进行清理,而rundll32按stdcall方式调用,期望是被调用者进行清理,这样退出时必定导致栈被破坏(不知道那个try能不能抓到这个例外)。然后,rundll32总是压进4个参数,如果被调用者希望的参数多于4个或者少于4个,退出后栈都不能平衡。另外就是这个自动加后缀的问题,除了微软自己的API之外,谁会用这样的命名方式把导出函数同时作一套ANSI和一套Unicode的呢?按照现在这个逻辑,没加W的一定被rundll32认为是ANSI的函数,这样就算被调用者理解rundll32调用的函数原型,还得考虑这个问题。
写了这么多,再回头来查文档。不查不知道,其实根本没必要去看Windows的源码,有好几篇微软的文章都提到了rundll32这些东西。
http://support.microsoft.com/kb/q164787/
KB164787.....90年代的老文了,里面我所讲到的基本都讲到了。还有一篇比较有趣的,就是说前面那个栈不平衡的问题老版本倒问题不大,可能是rundll32退出时系统全给清掉了;但是因为Vista下编译器优化的变化,导致非常容易出错。微软的程序员们干脆做了大改,先压N个字节的废物进栈,然后保存栈指针什么的。很蛋疼么。。。。http://blogs.msdn.com/b/oldnewthing/archive/2011/09/09/10208136.aspx
看来那堆当年的Windows“秘籍”什么的,用着都是有风险的!

2011年9月18日星期日

简单试用Windows Developer Preview 8102

BUILD大会上微软发布了下一代Windows系统,代号Windows 8的第一个公开预览版本Windows Developer Preview,build 8102。可以去如下地址下载这个公开版本(貌似限制了单线程,国内不容易一次性直接下完): http://msdn.microsoft.com/en-us/windows/apps/br229516 。我之前在山寨上网本安装过build 7850,因此这次也想来试试看。据说,此版本在虚拟机上安装比较麻烦(需要IOAPIC和ACPI2.0支持),且不能在没有NT6系统的情况下轻易和NT5系列系统双启动,而我目前没有任何空闲的机器和空闲的硬盘。好在这两天最新的VMWare Workstation 8出了,因此试试看。
我使用的计算机是一台老G965芯片组,奔腾双核E2160的机器。这个CPU支持amd64,但不支持VT-x硬件虚拟化技术,目前的主系统是32位的Windows Server 2003(公家的机器,接手来就是这系统,懒得重装了)。这个配置足以运行VMWare Workstation 8,但是不能虚拟64位客系统。下载32位版的Windows Developer Preview,直接新建个默认虚拟机,给1GiB内存,24GB磁盘。我忘了给安装过程截图,但一切还是比较顺利的。之后装VMWare Tools却出了问题,装上后桌面一出来是个黑屏。用简单快速的办法,PE启动,直接删除%windir%\system32\drivers下的vm3dmp.sys(VMWare SVGA 3D驱动)。貌似8102不再支持老的(NT5世代的)显卡驱动,因此VMWare SVGA II也装不了,只能用微软标准SVGA(这里改名Microsoft Basic Display什么的了,毕竟VGA本身就已经是个历史名词了)。因此,显示速度很难接受,但是还是勉强能跑的。
由于时间非常仓促,仅仅截了23张图来做个简单的说明。
这是默认的Metro UI“开始”。Metro UI的程序不能和桌面程序同时显示,可以说Metro UI的每个应用和传统桌面平等,都是整个窗口系统中的一个虚拟桌面。这个Metro的主页面看上去让人想起Windows Phone 7的UI,也许对洋大人来说很漂亮很新颖,但是不知对亚洲语言本地化之后的适应性怎么样。

Metro桌面下的IE10,全屏显示,在使用鼠标操作时,按右键能调出每个Metro应用下方的命令栏。这个新界面下的IE10不支持任何ActiveX插件,碰到需要插件的情况也不会提示安装。

Metro的控制面板。要么是极度简化,要么是根本没有写完,它的功能非常少,高级功能还是必须到传统桌面下的控制面板、


便笺,在主页面往右翻到最右边的某个tile(Metro用鼠标居然不支持全页直接拖动滚动,还要去拖滚动条!)

手写记事簿,应该能识别英文手写。

两个小游戏,看来微软做的这些demo的Metro应用就是在App Store上最泛滥的那种小东西。。。。


Metro UI不能让人太兴奋,因为毕竟这是给触摸设备优化的,谁愿意一台全功能的PC被限在这种框框里呢?我们去传统桌面吧。
开始菜单貌似滚蛋了,一点就进去Metro的主页。可以看到下一代Windows的新功能:在没有3D加速显示的情况下,桌面仍然能实现一定的透明特效。不过其他方面,这桌面和Windows 7目前看不出太大区别,除了Windows经典主题不知是干掉了还是把启用方法隐藏了。

带Ribbon的资源管理器窗口。Ribbon这个东西有人爱有人恨,我就不太喜欢。所有功能这么一下摆出来,反而更不好找。好在快捷键变化不大。另外,文件夹选项里的很多东西在Ribbon里面没有,比如那个臭名昭著的“隐藏受保护的系统文件”什么的。

自带装上光盘ISO格式镜像的功能(其实这是Mac用户的常用叫法,PC用户对应的概念是“虚拟光驱”)。其实微软早就做过这样的小工具,好像在XP SP1时代就有(貌似叫Virtual CD-ROM Control Panel),一直没直接放进系统里,不过我在build 7850就看到这功能直接加入系统了。其原理应该是把添加虚拟设备,虚拟插入光盘和删除虚拟设备自动化了一下。

作为古董软件专家,最关心的还是NTVDM的问题。在这个新系统版本的32位版中,NTVDM(前台称为“16位应用程序支持”)默认是关闭的,第一次运行16位程序的时候弹出来一个对话框要求确认打开此功能。看上去NTVDM的运行效果和Windows 7、build 7850没有什么区别。

5月的时候为介绍Windows 1.03的SDK写的小程序,在DOSBox中的Windows 1.01下,和在这个新系统版本下同时都能运行。版本号照例返回3.95。

Photoshop 6.0可以用,而更老的Photoshop 3.0就要开兼容模式否则启动会报内存不足(不知为何)。

Word 6.0 32位版和Word 95。7850下不能跑,报内存不足;8102下能跑了。

新任务管理器的界面,似乎主要新功能是能管理Metro UI下应用的运行情况。

新任务管理器“详细”选项卡与Windows Server 2003版任务管理器的对比。似乎Metro UI下的程序在这个32位版并非独立进程而是运行在一个服务下面的。另外2003的任务管理器看不到新DWM服务所在那个特殊用户组。(PS:这个版本的Windows Defender占用资源巨大,建议禁止)。

“性能”选项卡对比。其实早在Vista时代,任务管理器对内存使用的统计方法就已经有大变化了,两者在字面上显示的内存使用肯定会不一样。

服务和Windows 7相比增加了好几个,最令人注目的就是这几个代号Broker的东西,看描述,显然是和Metro UI WinRT程序相关的。

最新的微软拼音2012。选字框的默认字体大小变大。7850里面的还不是这个版本。

7850的控制面板中,输入法管理和Win7类似,7955换成了这个所谓“语言”的东西。话说为什么同是中文(简体),英文输入和带输入法的要算两个“Language”呢?

最后是番外的图。480M内存下,这个版本仍然能够启动到桌面(系统安装检测的要求是1G),占了300多M PF,估计什么都干不了了。。

新的复制文件界面,带有直观的流量显示功能(没试那个最新的覆盖文件选项框)。

总之感觉这确实还是个pre-beta版本,在虚拟机里的支持也不完善,估计确实是像微软说的,是给将来开发Metro UI WinRT应用的开发者热身所用。不过据说通过修改注册表关闭Metro UI之后(启动直接进入传统桌面,不能运行任何Metro UI的程序),系统还是比较稳定的。事实上由于时间过于仓促,像登录界面的Metro化、传统桌面下的IE10、Windows App Store、PowerShell 3.0之类非常重要的东西我都没来得及截图。下次有机会再补充吧。


更新:IE10桌面版目前功能停留在IE9的水平。User-agent如下:Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)

2011年8月26日星期五

让Windows 1.0x支持VGA分辨率

Windows 1.0x出来的时候,VGA并未定标准,因此M$并没有支持它。20多年后看来,EGA分辨率的Windows 1.0x是非常难看的(虽然这个分辨率在现代16:10或者16:9正方形像素显示的宽屏上的显示效果比4:3非正方形像素的EGA更正确)。怎样让它支持VGA呢?答案有两种。一是修改Windows 2.x的VGA驱动程序;二是将Windows 1.0x的EGA驱动程序改为支持VGA模式。
第一种方法我也试过,但是似乎有难以解决的逻辑问题存在(位图字体无法显示)。因此试试第二种。
首先最好取一个可以不安装而更改驱动程序的Windows 1.0x版本作为调试用。我使用了Windows 1.03 SDK中的debug版Windows 1.03内核,制作了一个这样的版本。

首先解决显示模式问题。DOS下切换显示模式有很多方法,最可靠和常用的方法是使用BIOS INT 10H中断的00号功能。这个调用相当简单,AH寄存器存显示模式,AL寄存器存00H,INT 10H即可。用反汇编器找到EGAHIRES.DRV(在“慢启动”免安装版本中的DISPLAY.DRV)中的此调用。

根据INT 10H文档(http://webpages.charter.net/danrollins/techhelp/0114.HTM),10H模式为EGA 640x350 16色。改为12H(VGA 640x480 16色)。后面那个CMP AL,10H也要改成12H,否则启动时切换显示模式会判定为切换失败而死机。
可以看到系统已进入VGA模式,但仍只能显示上半350像素,显示区域下方还有几行内容随鼠标移动而改变的花屏像素。仍需要修改。

驱动程序如何对GDI确定其显示模式呢?查找了一下Win3.1 DDK,发现了这个GDIINFO结构体,还有一个PBITMAP(硬件位图)结构体。

typedef struct tagGDIINFO {
   short int dpVersion;
   short int dpTechnology;
   short int dpHorzSize;
   short int dpVertSize;
   short int dpHorzRes;
   short int dpVertRes;
   short int dpBitsPixel;
   short int dpPlanes;
   short int dpNumBrushes;
   short int dpNumPens;
   short int futureuse;
   short int dpNumFonts;
   short int dpNumColors;
   unsigned short int dpDEVICEsize;
   unsigned short int dpCurves;
   unsigned short int dpLines;
   unsigned short int dpPolygonals
   unsigned short int dpText;
   unsigned short int dpClip;
   unsigned short int dpRaster;
   short int dpAspectX;
   short int dpAspectY;
   short int dpAspectXY;
   short int dpStyleLen;
   POINT dpMLoWin;
   POINT dpMLoVpt;
   POINT dpMHiWin;
   POINT dpMHiVpt;
   POINT dpELoWin;
   POINT dpELoVpt;
   POINT dpEHiWin;
   POINT dpEHiVpt;
   POINT dpTwpWin;
   POINT dpTwpVpt;
   short int dpLogPixelsX;
   short int dpLogPixelsY;
   short int dpDCManage;
   short int dpCaps1;
   long int dpSpotSizeX;
   long int dpSpotSizeY;
   short int dpPalColors;
   short int dpPalReserved;
   short int dpPalResolution;
} GDIINFO;

typedef struct tagPBITMAP {
   short bmType;
   short bmWidth;
   short bmHeight;
   short bmWidthBytes;
   BYTE bmPlanes;
   BYTE bmBitsPixel;
   long bmBits;
   long bmWidthPlanes;
   long bmlpPDevice;
   short bmSegmentIndex;
   short bmScanSegment;
   short bmFillBytes;
   short reserved1;
   short reserved2;
} PBITMAP;

两个结构体都包含了长、宽信息,2个连续的字长。对于640x350,最后按x86字节序拼成16进制应该是80 02 5E 01。
虽然Win3.1的显示模型和1.x相比已经有了巨大的变动,根据GDIINFO和PBITMAP结构在display.drv中都找不到完全对应的,但是80 02 5E 01却找到了2处。
干脆把这两处都改成80 02 E0 01,也就是640x480。
这下好,显示能扩展到屏幕底部了。但是,鼠标移动到350行以下时仍然不显示,而且350线下方仍然有一些花版的区域。

看来这有涉及逻辑的地方,我退缩了。
后来经过洋大人John Elliott的指点,才知道里面还有几处硬编码了屏幕高度和屏幕缓冲区大小,屏幕的乱区就是因为驱动用显存缓冲区后面的冗余空间做鼠标覆盖缓冲了。
这个减去屏幕高度应该是鼠标移动到350下面就不显示了。

把5E 01直接改为E0 01,鼠标就可以显示到350行以下去了。但是花屏区域仍然存在。
至于这个屏幕缓冲区大小,本来一开始也想到了的,但是思维被框死在按字节计算这个值(640x350x4位=112000字节)上了,结果居然是单个位面的大小28000字节(60 6D)。应该是EGA16色存储的4个位面是分开而不是交叉的,因此一次可以完整写一个位面。在这里找到这个:

没看明白这个call的用途,不过nop掉这个call,开菜单时鼠标轨迹就不擦掉了。看来果然这个和鼠标有关。改掉为38400字节( 00 96 )。
这样下来开菜单时鼠标箭头的背景就变成黑色了,估计是擦鼠标箭头读了更新后那一块地址上应有的内容作为鼠标箭头背景,而其实原有屏幕内容却还保存在原位置(就是那些花版的地方)。

继续查这个28000,还发现2处一样的指令。


但三处都修改后,花版仍然存在。几乎又要放弃的时候,偶然往后跟踪那三个鼠标相关的调用,都在其中某个子程序发现了一个奇怪的常数28160(00 6E)。

我没搞懂这的逻辑(汇编不好+没有Win1 DDK+Win3.1 DDK的实例显卡驱动没认真看过),但是直觉上认为这个28160就是28000加上两行(一行640位=80字节)。改成38400+2x640/8=38560(A0 96)呢?果断试试看。三处全部改完,好,奇迹发生,乱屏部分终于消失了。

总结一下,把EGAHIRES.DRV进行修改,先把INT 10H部分改掉(B8 10 00 CD 10改成B8 12 00 CD 10,下面的3C 10 B8 00 00 改成3C 12 B8 00 00),那一处硬编码改掉(81 E9 5E 01改成81 E9 E0 01),把所有的BF 60 6D替换为BF 00 96,81 C0 00 6E替换为81 C0 A0 96就能让这个EGA驱动变成VGA的了。
把安装盘里面的这个EGAHIRES.DRV如法炮制,就能制作出可以支持VGA的标准安装版Windows 1.0x。
直接修改装好的1.01的WIN100.BIN,也可以实现。而且这个改法对于Windows 1.01-1.04都有效。

虽然还没搞懂最后那几个关于鼠标描绘部分修改的逻辑,但是至少我们又研究出了微软都没有几个人还记得的东西。
下次有时间把Windows 2.1/286的VGA驱动改到Win1.03使用的方法也写一下(不完善,位图字体不能用)。
这里是改过的Windows 1.03 EGAHIRES.drv和改过的已安装版Windows 1.01(支持PS/2鼠标)的下载。
http://www.mediafire.com/?fw1c10q7bxgyw
感谢 kalakala(尝试Hack Windows 2.0x 驱动的高人),John Elliott的支持和指教。
John Elliott还实现了SVGA 800x600x16色,写了自动补丁程序。请看:
http://www.seasip.info/Misc/win1.html

2011年8月19日星期五

有关山寨PSP

山寨PSP自从丁果A320开始草创,除开之前未流行起来的杂七杂八的之外,到今天已经发展了两代。
最初是06,07年左右,一些MP4方案商开始开发MP4用的FC模拟器,然后很快就初步取得成功。但是当时FC模拟不过是那些MP4的一些附加功能,而且那些MP4的按键布局仍然是传统布局,因此并不能称为山寨PSP。
2008年中,这个形势有了很大的改变。炬力、凌阳的MP4方案都加入了模拟器的支持,如果我没记错,瑞芯微和君正也有。当MP4方案固件支持的游戏模拟器多到一定程度(FC,GB,SFC,MD和GBA)时,强大的东西出现了。
2009年初,一种叫做丁果A320的机器横空出世。它外观神似没有上屏的NDSL,2.8 QVGA屏,似乎使用了某个非常强大的方案,官方固件能模拟FC,GB/GBC,GBA,SFC,MD,NEOGEO之类。这机器很快就流传到了洋大人手里,在被逆向后,进行自制开发者不少,甚至有洋大人为它自制了一个Linux系统Dingux。由于该机的可研究性,出来时这机器500多块,至今全新机还要400块左右。这样的机器仍然不便宜,而且那个强大的方案商(只知道主控是君正4732)似乎并没有把这个作为主打产品后续开发。不过就过了几个月,真正的山寨PSP就出现了。
金星JXD,一个MP4市场上有点名气的公司;申江科技,一个貌似也出现了几年的MP4类方案商;凌阳,一个已经在低端播放器市场摸爬滚打了多年的DSP公司。三者一拍即合,SPMP8000芯片,申江的固件,金星JXD的设计和对固件的修改(JXD和申江的关系很特别,能做到很多申江公版没有的东西),打造了第一代PSP外形MP4。这种机器,以ARM9为核心,貌似是eCOS为OS,以以往做的FC,GB模拟器和抄开源代码的GBA(具体是gPSP),SFC之类模拟器为其支持游戏功能的关键部分。首先是金星JXD的JXD1000,然后是申江板、申江方案的一批山寨机器。这些机器就是山寨PSP的第一代。
第一代机器基本性能和视频音频播放性能都还过得去,但问题是对H264视频支持一般(早期版固件不支持),另外固件中的模拟器除了金星后期对GBA模拟器进行了一些更新外,从未改动过。导致该机模拟只有FC和GB效果较好(但也不支持多数FC的扩展卡带),SFC模拟器拖慢严重,不支持任何扩展卡带;GBA模拟器除了金星后期版外,全都有时快时慢的问题,而且很多大量使用mode5的游戏无法运行。当然在市场上来看,JXD1000以300多块/4G,山寨公版以200块出头/4G来算,在山寨市场如华强北,和淘宝上销路都不错。至今在淘宝搜索PSP,仍然能看到一大批此类一代山寨PSP。
一年过去了。申江/凌阳方案的山寨PSP一代几乎占领了市场,金星甚至把触摸屏都开发到这方案上了。但是,机器模拟的问题始终没有真正解决。此时,炬力开始给力了。虽然之前凌阳方案威武的时候,炬力早有支持FC/GB/GBC/SFC的方案,但是问题远远比凌阳多,也不支持480x272的PSP标准4.3屏。而到了2010年中,炬力升级了其方案(所谓G100,ATJ22xx系的改进版),这次CPU达到500MHz,支持H264,以比当年君正方案A320低得多的价格实现了16位街机甚至PS游戏的模拟。申江等几家公司很快就跟进推出了板子,金星最早出成品JXD3000,然后到4,5月左右开始出现公版的。这就是所谓的二代山寨PSP。
二代山寨PSP在性能上有巨大的提高,但是价格也至少提高了几十块钱。目前模拟PS,纯2D的东西还可以,但是问题太多太多(比如DQ7引擎完全不行,3D不仅慢,而且对于很多游戏会出现贴图错误)。街机,能跑的都还可以,但是有frameskip,声音奇差。倒是此方案模拟GBA已经能够满帧了,这不错。
至于瑞芯微,已经全面转向Android低端方案;君正虽然继续出,丁果跟进出了一些后续机,但都曲高和寡。
其实,在一线市场非智能设备的前途越来越窄了。山寨PSP这种怪物,面对的主要是国内二三线市场,以及向第三世界国家出口。山寨货有个特点,功能不求精而求多,重噱头不重细节。山寨PSP在很多地方也体现了这个特点。最首要的是其游戏模拟器功能,不出新方案绝对不改进,完全在浪费CPU的性能;然后就是游戏手感方面,看起来此类固件的编写和测试者只要游戏可以运行就通过了,完全没有考虑过真正的掌机开发要在人体工程学上下多少功夫,所谓手感对游戏性的影响等方面,导致很多人因为手感而放弃山寨PSP。另外,这些固件设计者只是一味山寨界面,殊不知UI设计对使用者感受的影响。现在PSP的正统后继者PSVita也马上要出了,掌机从GB进化到GBA,进化出NDS和PSP,到现在的3DS和PSVita,如今已经跨入了第四代。在小鬼子们的掌机在和洋大人老乔的iOS设备作生死搏斗的时候,深圳制造和东莞制造的山寨们在出这种四不像的MP4来抢占穷人的市场。可以说,除了成熟稳定的MTK山寨机之外,山寨PSP,山寨本之类的东西,山寨PSP便宜就有人要,山寨本成本和性能永远无法和二手本相比,现在接近死亡也是必然的了,成本已成了此类山寨货的唯一优势。这是一个玩了3台山寨机,2台山寨本,5个山寨PSP和MP4的人的感受。

2011年7月22日星期五

老乔所最痛恨的东西——Flash .swf播放器上了AppStore

众所周知,苹果的老乔一贯讨厌Flash。这应该和从Macromedia时代开始,Mac OS X的Flash插件一贯优化差,极端情况下可以让Mac笔记本仅仅开浏览器的情况下,电池待机时间减少一半以上有关。
基于这个理由,加上Flash并非为触摸屏设计的东西,从2007年iPhone初代开始,苹果一贯不准备把Flash引入到iOS上,App Store早期甚至明令禁止任何通过模拟/虚拟手段而非原生的应用。当然这个禁令取消了,Adobe让Flash Builder能做出半原生的iOS App,后来也曾经出现过不少能通过在线代理之类间接支持Flash的app,包括很多浏览器类app,但是它们几乎无一例外只对Flash视频网站有较好的支持,而对Flash游戏、Flash PV和广告(啪!)支持不好。
真正能运行.swf文件的iPhone app,之前越狱界曾经出现过移植开源Flash播放器gnash的。然而,有这样一个真正的SWF player,这两个月出现在了App Store上。

它的名字当然就是——中国卡通。
这个应用的iTunes介绍如下:

(PC/Mac请打开http://itunes.apple.com/jp/app/id432260573?mt=8)
其中并未提到任何和Flash有关的介绍。然而,通过简单的研究,很容易就能发现它其实是播放SWF的。

根据这堆破图,应该能够判断这个程序是从其网站(具体地址需要抓包才知道,反正那个游戏列表是http://m.jqbar.com/。)下载某些东西到本地,然后运行的玩艺。
此App有个把网站上的那些可以播放的小游戏或者PV之类下载到本地的选项。

随便点了一个纵版、一个横版的小游戏和一个PV(某神曲的),下载到本地。
由于这个Touch四代乃越狱机,直接用iFunBox打开这个App的安装目录。Documents下没有内容,再找了一下,发现存在本地的东西在/var/mobile/Applications/安装目录/Library/Documentation/local/下,里面赫然放着三个swf文件。果断拷出来丢进浏览器,结果神了,真是Flash的swf文件无疑。

至于那个cfg文件呢?打开来看,有两种。游戏的是一种,动画的是另一种。
它们都是UTF-8编码的类XML文件,其共有结构如下:
<?version="1.0" encoding="UTF-8" ?>
<!DOCTYPE config SYSTEM "config.dtd">
<!-- 文件类型声明 -->
<defines>
<file_info content_ID="1b97fb3e99db3bc7" content_level="10" zcontent_type="media" mobile_operate_type="Touch_Nopad" />
<!-- 文件ID(貌似是某种UUID?),其他的除了游戏多一个hotkey_for_zoom属性外没有 -->
<operate_define />
<display_define screen_direction="Horizon" zoom_size="Fit" quality="high" />
<!-- 显示定义,横屏竖屏(Horizon和Vertical),放大,Flash的质量之类 -->
<sound_define />
</defines>
<!-- 定义部分 -->

对于游戏,operate_define、sound_define里还包了东西,而且还有另外结构。。
 <operate_define default_mouse_move_pace="." default_long_press_lock_time="." touchsize="." >
<mouse_normal_define name="模拟鼠标" />
<mouse_table_define name="模拟菜单" />
<!-- 和鼠标模拟触屏相关的参数,默认移动速度,长按锁定,触摸屏感应大小什么的 -->
<touch_define>
<touch_map button_name="left" org="2" button_hor_pos="10" button_ver_pos="20" button_map_to="37" />
<touch_map button_name="down" org="2" button_hor_pos="70" button_ver_pos="20" button_map_to="40" />
<touch_map button_name="right" org="2" button_hor_pos="130" button_ver_pos="20" button_map_to="39" />
<touch_map button_name="up" org="2" button_hor_pos="70" button_ver_pos="80" button_map_to="38" />
<touch_map button_name="a" org="3" button_hor_pos="20" button_ver_pos="20" button_map_to="17" />
<touch_map button_name="b" org="3" button_hor_pos="20" button_ver_pos="80" button_map_to="32" />
</touch_define>、
<!-- 虚拟键盘,button_name不言而喻,org貌似是组别(?),button_hor_pos和button_ver_pos是按钮的位置(相对于屏幕左下角),
button_map_to是虚拟键盘对应的编码,除开方向键外其它都是对应的ASCII码 -->
</operate_define>
<sound_define mute="false" volume="4" sound_device="Speaker" /> <!--声音音量 -->
<network_define score_type="var" score_var_name="_level0.score" submit_url="http://m.jqbar.com/submit.aspx" autotag="296@297" />
<!--似乎是和在线提交得分相关的,那个score_var_name应该是指AS本地存储的变量名吧 -->
<txt_define> 里面是一个UTF-8的HTML... </txt_define> <!-- 貌似是游戏的帮助信息 -->

下一步得试试看能不能把自己的Flash SWF文件放进这个app让它播放。首先试试IOSYS的几个东方Flash PV,直接套用那个神曲MV的.cfg,也不管那个content_ID了,直接丢进去。出人意料的是,居然直接播放成功。貌似此app目前并不会真正验证那个ID。
至于播放速度,那就很雷了,目测就10-13fps的样子(很可能是touch4本身就不够快的原因)。顺便说说,国内的Flash PV很少像IOSYS的那样,用25fps以上的时基做的,长期以来都是如此,不知为何。



至于游戏,就得根据游戏本身的键位自己修改虚拟键盘touch_define(其实应该还有重力感应的define,我没下重力感应的游戏来研究)。结果测试了三个Flash游戏,DOOM Flash版,两个打飞机,分别用雷电2.cfg、陨石大战.cfg修改,丢进去。
结果,DOOM Flash版无法运行(一直显示正在载入),其他两个游戏运行极为缓慢。然而最要命的是,这个虚拟键盘不支持通过多点触摸实现多个键同时按下,导致这两个STG基本没法玩。。。。


当然这个app最大的问题是,不对应视网膜显示和iPad屏幕。Flash是矢量格式,在高分屏上变成马赛克是非常丑陋的。据某有iPad2的测试,iPad2上这个app运行swf的速度可以比Touch4快1倍。。。
这个App的纪念意义是很大的,毕竟App Store之前没出现过能完全离线播放本地Swf文件的任何App。但是由于该App可以从外部下载任意数据并运行,潜在地违反了开发者协议的某条款。如果有高人分析出了其Flash解释器的漏洞,攻击该app使用的网页,插入恶意Swf,那么就囧了。因此我看苹果一旦再次审核这个,很可能有下架的危险。

进一步从那个http://m.jqbar.com/入手,发现这个jqbar和这个应用开发者之间的关系有待研究,因为jqbar自己也有类似的可以播放Flash的应用——请参考http://www.jqbar.com/Download/。由于日本的Store这个没上架,我只能下左边那个破解专用版来一试。



果然,无论是界面,还是功能来看,甚至是.app的文件名,本地文件与Cache存放的目录,这个集趣游戏都和中国卡通几乎一样,只不过界面控件是原生的。再仔细看那个“大款工作室”,找找他们发布的其他App你肯定会发现它其实就是这个集趣,或者百玩的马甲!有此等神技术的公司,为何还闷着做这种偷偷摸摸,应用介绍里连Flash的大名都不敢提起的app呢?从他们的官方博客来看,他们的程序是今年才开始上架的,貌似性能上还有很多问题。再看他们的论坛,还可以发现早就被广告机所完全占领了。。。
我没仔细看中国卡通和这个集趣吧的.app里面的可执行文件和资源文件,搜索字串adobe找到的都是用ImageReady/PS做PNG写入的metadata,搜shockwave找到的只有一个mimetype。倒是里面那个D.dat,是libmad GPL MP3解码库的一个头文件,又看不到有libmad的动态库,看来这App可能还涉及到违反GPL;fonts.fnt貌似是个结构不明的字体文件;还有几个dat貌似是MP3解码IDCT用的查找表。
估计腾讯什么的可以考虑把这帮人收编过去,好好研究下他们怎么在iOS平台直接播放swf的。我看,很可能还是用了类似Gnash的开源库实现的,除非开发者有这工夫把执行文件里有关Adobe的字串全部干掉或者干脆把可执行文件加壳(PS:AppStore app的可执行文件加了壳,苹果会怎么去审核它呢?)

本来还录了这个中国卡通app的运行视频,可惜在国内网站上。这里干脆从略了。