等了很久的《轩辕剑》,近期终于开播了(有同追的大牛么= =)~在网上找了找,貌似只有迅雷那里有比较高清的版本(转录的TV版720P),但下载回来发现格式是.xv而非常见的视频格式,迅雷为了“垄断片 源”,自创.xv视频格式,只能由迅雷看看播放器播放,对于我这种伪完美主义者~当然不肯轻易就范了
于是在网上找迅雷XV格式转换器,搜了一下发现还真有这东西,很简单的一个小程序,目前的最新版叫XVE7s,作者是“伪红学家”,地址:http://tiancaihb.ixiezi.com/2012/06/19/xve7/
这个版本的XVE还新加了个“一秒转换”功能,听起来很强大,下载试了下,很有效,的确是秒速把.xv转换成了.flv。当然了,速度这么快是直接对原始xv文件覆盖写入的(不然光copy一份就要好久呢)。
感觉这个小程序很神奇,也很简洁,习惯性拖IDA看了下,没多少sub,刨去MFC框架估计核心代码不会很多(真的很少- -!!),于是就动手分析了一下~
暂时只逆了1秒转换部分,支持flv,普通模式还没看。
.text:004015AF mov ebp, ds:fgetc
.text:004015B5 test eax, eax
.text:004015B7 jz loc_4017D0 ; 是否使用1秒转换
.text:004015BD mov eax, [esp+11B8h+szSourceFile]
.text:004015C4 push offset Mode ; "rb+"
.text:004015C9 push eax ; Filename
.text:004015CA call ds:fopen ; 打开.xv文件
.text:004015D0 mov esi, eax
.text:004015D2 push 0 ; Origin
.text:004015D4 push 200000h ; Offset
.text:004015D9 push esi ; File
.text:004015DA call ds:fseek
.text:004015E0 add esp, 14h
.text:004015E3 lea edi, [esp+11B8h+buffer]
.text:004015EA mov ebx, 400h
.text:004015EF
.text:004015EF loc_4015EF: ; CODE XREF: convert_file+DBj
.text:004015EF push esi ; File
.text:004015F0 call ebp ; fgetc
.text:004015F2 mov [edi], eax
.text:004015F4 add esp, 4 ; 从0x200000偏移处读取1024字节到DWORD buffer[0x400]
.text:004015F7 add edi, 4
.text:004015FA dec ebx
.text:004015FB jnz short loc_4015EF
.text:004015FD mov eax, [esp+11B8h+tOff1]
.text:00401604 mov ebx, 4Ch
.text:00401609 sub ebx, eax
.text:0040160B and ebx, 0FFh ; flag = 0x4C – (char)buffer[1]
.text:00401611 add eax, ebx
.text:00401613 cmp al, 4Ch
.text:00401615 jnz loc_4017C2 ; if ((flag + buffer[1]) == 0x4C)
.text:00401615 ; 其实这句可以省略,代入flag展开后就是
.text:00401615 ; (0x4C – buffer[1] + buffer[1]) == 0x4C
.text:0040161B mov ecx, [esp+11B8h+tOff2]
.text:00401622 add ecx, ebx
.text:00401624 cmp cl, 56h
.text:00401627 jnz loc_4017C2 ; if ((flag + buffer[2]) == 0x56)
.text:00401627 ; 对文件格式的检查
.text:0040162D mov edx, [esp+11B8h+szSourceFile]
.text:00401634 lea eax, [esp+11B8h+Dest]
.text:00401638 push edx
.text:00401639 push offset asc_4042F8 ; "
.text:0040163E push eax ; Dest
.text:0040163F call ds:sprintf
.text:00401645 mov edi, [esp+11C4h+unknown_ecx_para]
.text:00401649 add esp, 0Ch
.text:0040164C lea ecx, [esp+11B8h+Dest]
.text:00401650 push ecx
.text:00401651 mov ecx, edi
.text:00401653 call list_print_text ; 输出目标文件名(源文件名.flv)
.text:00401653 ; 以及各种信息
.text:00401658 push offset unk_4042EC
.text:0040165D mov ecx, edi
.text:0040165F call list_print_text
.text:00401664 push offset unk_4042D8
.text:00401669 mov ecx, edi
.text:0040166B call list_print_text
.text:00401670 push 0 ; 开始解码
.text:00401672 push 200000h ; Offset
.text:00401677 push esi ; File
.text:00401678 call ds:fseek
.text:0040167E mov edi, ds:fputc
.text:00401684 push esi ; File
.text:00401685 push 46h ; Ch
.text:00401687 call edi ; fputc
.text:00401689 add esp, 14h
.text:0040168C lea ebp, [esp+11B8h+tOff1] ;
.text:0040168C ; for (i = 0; i < 3; i++) {
.text:0040168C ; data = (char)buffer[1 + i] + flag;
.text:0040168C ; fputc(data, fp);
.text:0040168C ; }
.text:00401693 mov [esp+11B8h+progress], 3
.text:0040169B
.text:0040169B loc_40169B: ; CODE XREF: convert_file+199j
.text:0040169B mov edx, [ebp+0]
.text:0040169E push esi ; File
.text:0040169F add edx, ebx
.text:004016A1 and edx, 0FFh
.text:004016A7 push edx ; Ch
.text:004016A8 call edi ; fputc
.text:004016AA mov eax, [esp+11C0h+progress]
.text:004016AE add esp, 8
.text:004016B1 add ebp, 4
.text:004016B4 dec eax
.text:004016B5 mov [esp+11B8h+progress], eax
.text:004016B9 jnz short loc_40169B ;
.text:004016B9 ; for (i = 0; i < 0x3FC; i++) {
.text:004016B9 ; data = (char)buffer[4 + i] + flag;
.text:004016B9 ; fputc(data, fp);
.text:004016B9 ; }
.text:004016BB lea ebp, [esp+11B8h+tOff4]
.text:004016C2 mov [esp+11B8h+progress], 3FCh
.text:004016CA
.text:004016CA loc_4016CA: ; CODE XREF: convert_file+1C7j
.text:004016CA mov eax, [ebp+0]
.text:004016CD push esi ; File
.text:004016CE add eax, ebx
.text:004016D0 and eax, 0FFh
.text:004016D5 push eax ; Ch
.text:004016D6 call edi ; fputc
.text:004016D8 mov eax, [esp+11C0h+progress]
.text:004016DC add esp, 8
.text:004016DF add ebp, 4
.text:004016E2 dec eax
.text:004016E3 mov [esp+11B8h+progress], eax
.text:004016E7 jnz short loc_4016CA
.text:004016E9 mov ebx, ds:fseek
.text:004016EF push 0 ; Origin
.text:004016F1 push 20000Ah ; Offset
.text:004016F6 push esi ; File
.text:004016F7 call ebx ; fseek
.text:004016F9 push esi ; File
.text:004016FA push 20h ; Ch
.text:004016FC call edi ; fputc ;
.text:004016FC ; 修正文件头
.text:004016FE push 0 ; Origin
.text:00401700 push 0 ; Offset
.text:00401702 push esi ; File
.text:00401703 call ebx ; fseek
.text:00401705 push esi ; File
.text:00401706 push 46h ; Ch
.text:00401708 call edi ; fputc
.text:0040170A push esi ; File
.text:0040170B push 4Ch ; Ch
.text:0040170D call edi ; fputc
.text:0040170F push esi ; File
.text:00401710 push 56h ; Ch
.text:00401712 call edi ; fputc
.text:00401714 push esi ; File
.text:00401715 push 1 ; Ch
.text:00401717 call edi ; fputc
.text:00401719 add esp, 40h
.text:0040171C push esi ; File
.text:0040171D push 5 ; Ch
.text:0040171F call edi ; fputc
.text:00401721 push esi ; File
.text:00401722 push 0 ; Ch
.text:00401724 call edi ; fputc
.text:00401726 push esi ; File
.text:00401727 push 0 ; Ch
.text:00401729 call edi ; fputc
.text:0040172B push esi ; File
.text:0040172C push 0 ; Ch
.text:0040172E call edi ; fputc
.text:00401730 push esi ; File
.text:00401731 push 9 ; Ch
.text:00401733 call edi ; fputc
.text:00401735 push esi ; File
.text:00401736 push 0 ; Ch
.text:00401738 call edi ; fputc
.text:0040173A push esi ; File
.text:0040173B push 0 ; Ch
.text:0040173D call edi ; fputc
.text:0040173F push esi ; File
.text:00401740 push 0 ; Ch
.text:00401742 call edi ; fputc
.text:00401744 add esp, 40h
.text:00401747 push esi ; File
.text:00401748 push 0 ; Ch
.text:0040174A call edi ; fputc
.text:0040174C push esi ; File
.text:0040174D push 0FFh ; Ch
.text:00401752 call edi ; fputc
.text:00401754 push esi ; File
.text:00401755 push 1Fh ; Ch
.text:00401757 call edi ; fputc
.text:00401759 push esi ; File
.text:0040175A push 0FFh ; Ch
.text:0040175F call edi ; fputc
.text:00401761 push esi ; File
.text:00401762 push 0F1h ; Ch
.text:00401767 call edi ; fputc
.text:00401769 push esi ; File
.text:0040176A call ds:fclose
.text:00401770 mov esi, [esp+11E4h+szSourceFile]
.text:00401777 lea ecx, [esp+11E4h+NewFilename]
.text:0040177E push esi
.text:0040177F push offset aS_flv ; "%s.flv"
.text:00401784 push ecx ; Dest
.text:00401785 call ds:sprintf
.text:0040178B lea edx, [esp+11F0h+NewFilename]
.text:00401792 push edx ; NewFilename
.text:00401793 push esi ; OldFilename
.text:00401794 call ds:rename ; 重命名.xv文件为.flv
.text:0040179A add esp, 40h
.text:0040179D test eax, eax
.text:0040179F jz short loc_4017AF
.text:004017A1 mov ecx, [esp+11B8h+unknown_ecx_para]
.text:004017A5 push offset unk_404298
.text:004017AA call list_print_text
.text:004017AF
.text:004017AF loc_4017AF: ; CODE XREF: convert_file+27Fj
.text:004017AF mov ecx, [esp+11B8h+unknown_ecx_para]
.text:004017B3 push offset aK ; "转换完成\r\n"
.text:004017B8 call list_print_text
然后人工翻译了成C码,调试了一下,可以成功将.xv转换成.flv(xv文件须合法,反正够我看轩辕剑的了= =)
#include <stdlib.h>
int convert_file(char *szSourceFile, int bIsFastConv)
{
char szNewFileName[256] = {0};
int buffer[0x400];
int i;
char flag;
char data;
if (bIsFastConv) { // 一秒转换模式
FILE *fp = fopen(szSourceFile, "rb+");
if (!fp) {
printf("未找到文件.\n\n");
return 0;
}
fseek(fp, 0x200000, 0);
for (i = 0; i < 0x400; i++) {
buffer[i] = fgetc(fp);
}
flag = 0x4C – (char)buffer[1];
if (flag + (char)buffer[2] == 0x56) {
// 开始解码
fseek(fp, 0x200000, 0);
fputc(0x46, fp);
for (i = 0; i < 3; i++) {
data = (char)buffer[1 + i] + flag;
fputc(data, fp);
}
for (i = 0; i < 0x3FC; i++) {
data = (char)buffer[4 + i] + flag;
fputc(data, fp);
}
fseek(fp, 0x20000A, 0);
fputc(32, fp);
// 修正文件头
fseek(fp, 0, 0);
fputc(70, fp);
fputc(76, fp);
fputc(86, fp);
fputc(1, fp);
fputc(5, fp);
fputc(0, fp);
fputc(0, fp);
fputc(0, fp);
fputc(9, fp);
fputc(0, fp);
fputc(0, fp);
fputc(0, fp);
fputc(0, fp);
fputc(255, fp);
fputc(31, fp);
fputc(255, fp);
fputc(241, fp);
fclose(fp);
sprintf(&szNewFileName[0], "%s.flv", szSourceFile);
rename(szSourceFile, &szNewFileName[0]);
printf("转换完成.\n输出文件: %s\n\n", szNewFileName);
} else {
printf("文件格式不正确.\n\n");
return 0;
}
} /*else { // 常规模式(未完成)
}*/
return 1;
}
int main(int argc, char **argv)
{
char szFileName[256] = {0};
printf("迅雷XV格式转换器 XVE7s 秒速转换逆向版本\n Code by Naylon\n http://hi.baidu.com/naylonslain");
if (argc > 1) {
convert_file(argv[1], 1);
} else {
// Test Input: "D:\Downloads\000.xv"
while (1) {
scanf("%s", &szFileName[0]);
convert_file(szFileName, 1);
memset(&szFileName[0], 0, 256);
}
}
return 0;
}
本文仅作学习研究
5 comments
Skip to comment form
I had some trouble compiling the code at first, but I resolved. One proble I couldn't fix was this line as causing some problem so I commented it out. " if (flag + (char)buffer[2] == 0×56) {" .
Thanks for the code, I couldn't download this from 115 because I couldn't register for an account since I don't have an active cell phone number 🙁
Awesome post.
Author
Thx for ur comment.
But i'm confused since i have no trouble compiling the code using VC6. And idk what's wrong with "if (flag + (char)buffer[2] == 0×56) {". Did i make a mistake? Forgiving my bad coding style 🙁
115 is easy to register, maybe i can help u if u met some troubles.
btw…you're not Chinese, are you? How did u know my blog? XD
Yeah, I am chinese. I didn't have any problem compiling that line, but that boolean statement keep return false when I try to convert the xv files so i just comment it out.
I found your blog when I was search for another link to download the XVE7s.
By the way, where did you learn your IDA pro skill from?
学习英文来的。。太霸道了。
well,thank you for your nice project,you have done something I intended for long but never get down to.the xv converter is a good work which is said to be developed by a now CMU student when he was at high school some a decade ago,and xv converter project is now open source sine 2013.