酷狗7 kugou.skn文件格式分析

首先在这里申明, 只用于学习, 不作其它用, 其它问题别找我.
因为这两天想把以前vcl写的播放器用fmx写下,加强下fmx的熟练度, 看到以前的图片资源又少,也不怎么好看,寻思着扒下kg的资源, 发现他的kugou.skn文件不是压缩文件, 于是想它是不是加密了,OD载入分析了下他并没有加密, 于是用WinHex打开文件, 明文发现他的前面是存储的文件名称, 往后面是图片的资源, 由是着手分析了下

输入图片说明

首先前4个字节发现为文件的数量 32 07 00 00
接下来4字节为这条记录的长度
再来就1字节为文件名的长度, 文件名为Unicode格式
再最后4个字节 32 01 00 00 存储的为该文件的长度
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
循环读取文件长次数之后就是图片的起始位置了, 可以看到下面,没有加密的.,

酷狗7 kugou.skn文件格式分析_第1张图片

用Delphi写了个类处理这个文件, 下面是代码

  // 7.5.85.14422
  // kugou.skn
  // ying32
  // QQ:1444386932
 
  TKugouSkinRead = class
  public
  type
     PKugouResRec = ^TKugouResRec;
     TKugouResRec = packed record
       Index: Integer;
       FileSize: Integer;
       FileName: string;
       Position: Int64;
     end;
  private
     FList: TList;
     FFileName: string;
     FMemStream: TMemoryStream;
     function GetFileName(P: Pointer): string;
  public
     constructor Create;
     destructor Destroy; override;
     procedure LoadFromFile(AFileName: string);
     procedure Clear;
     procedure Extract(AIndex: Integer; out AStream: TMemoryStream); overload;
     procedure Extract(AFileName: string; out AStream: TMemoryStream); overload;
     procedure ExtractAll(ADir: string);
     procedure ExtractToFile(AIndex: Integer; AFileName: string = '');
  end;
  
implementation

{ TKugouSkinRead }

procedure TKugouSkinRead.Clear;
var
  I: Integer;
begin
  for I := 0 to FList.Count - 1 do Dispose(FList[I]);
  FList.Clear;
end;

constructor TKugouSkinRead.Create;
begin
  inherited Create;
  FList := TList.Create;
  FMemStream := TMemoryStream.Create;
end;

destructor TKugouSkinRead.Destroy;
begin
  Clear;
  FList.Free;
  FMemStream.Free;
  inherited;
end;

procedure TKugouSkinRead.Extract(AIndex: Integer; out AStream: TMemoryStream);
var
  Buffer: array of Byte;
  Item: PKugouResRec;
begin
  if (AIndex >= 0) and (AIndex < FList.Count) and (Assigned(AStream)) then
  begin
    AStream.Position := 0;
    Item := PKugouResRec(FList[AIndex]);
    SetLength(Buffer, Item^.FileSize);
    try
      FMemStream.Position := Item^.Position;
      FMemStream.Read(Pointer(Buffer)^, Item^.FileSize);
      AStream.Write(Pointer(Buffer)^, Item^.FileSize);
      AStream.Position := 0;
    finally
      SetLength(Buffer, 0);
    end;
  end;
end;

procedure TKugouSkinRead.Extract(AFileName: string;
  out AStream: TMemoryStream);
var
  I: Integer;
begin
  for I := 0 to FList.Count - 1 do
    if SameStr(LowerCase(GetFileName(FList[I])), LowerCase(AFileName)) then
    begin
      Extract(I, AStream);
      Exit;
    end;
end;

procedure TKugouSkinRead.ExtractAll(ADir: string);
var
  I: Integer;
  Mem: TMemoryStream;
begin
  Mem := TMemoryStream.Create;
  try
    if not DirectoryExists(ADir) then
      CreateDir(ADir);
    if LastDelimiter('\', ADir) <> Length(ADir) then
      ADir := ADir + '\';
    for I := 0 to FList.Count - 1 do
    begin
      Mem.Clear;
      Extract(I, Mem);
      Mem.SaveToFile(ADir + GetFileName(FList[I]));
    end;
  finally
    Mem.Free;
  end;
end;

procedure TKugouSkinRead.ExtractToFile(AIndex: Integer; AFileName: string);
var
  Mem: TMemoryStream;
begin
  Mem := TMemoryStream.Create;
  try
    Extract(AIndex, Mem);
    if Mem.Size > 0 then
      if Length(AFileName) = 0 then
        Mem.SaveToFile(GetFileName(FList[AIndex]))
      else Mem.SaveToFile(AFileName);
  finally
    Mem.Free;
  end;
end;

function TKugouSkinRead.GetFileName(P: Pointer): string;
begin
  Result := '';
  if Assigned(P) then
    Result := PKugouResRec(P)^.FileName;
end;

procedure TKugouSkinRead.LoadFromFile(AFileName: string);
var
  FileCount, I: Integer;
  Item: PKugouResRec;
  RecLen: Integer;    // 每条记录长度
  LNameLen: Byte;  // 文件名的长度
  LName: array[Byte] of Char;
  FileStartPosi: Int64;
begin
  Clear;
  FFileName := AFileName;
  try
    FMemStream.LoadFromFile(AFileName);
    FMemStream.Read(FileCount, 4);
    for I := 1 to FileCount do
    begin
      New(Item);
      Item^.Index := I;
      FillChar(LName, SizeOf(LName), 0);
      FMemStream.Read(RecLen, 4);
      FMemStream.Read(LNameLen, 1);
      FMemStream.Read(LName, LNameLen);
      Item^.FileName := string(LName);
      FMemStream.Seek(RecLen - (4 + 1 + LNameLen) - 4, soCurrent);
      FMemStream.Read(Item^.FileSize, 4);
      FList.Add(Item);
    end;
    FileStartPosi := FMemStream.Position;
    for I := 0 to FList.Count - 1 do
    begin
      Item := PKugouResRec(FList[I]);
      Item^.Position := FileStartPosi;
      Inc(FileStartPosi, Item^.FileSize);
    end;
  except
  end;
end;  

转载于:https://my.oschina.net/ying33/blog/1575647

你可能感兴趣的:(酷狗7 kugou.skn文件格式分析)