首页
社区
课程
招聘
[原创]逆向windows数字签名验证过程
发表于: 2011-6-8 15:01 16229

[原创]逆向windows数字签名验证过程

2011-6-8 15:01
16229

临近期末要考试,目前只逆了一个函数,BOOL CryptCATAdminAcquireContext(HCATADMIN *phCatAdmin,GUID *pgSubsystem,DWORD dwFlags),待有时间后再一一逆完。没什么技术含量,高手飘过。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (18)
雪    币: 278
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
       雪雪雪     看看看看看看看看看 
 雪雪雪雪雪雪            看     
     雪        看看看看看看看看看看看
  雪雪雪雪雪雪雪雪    看 看  看  看 看
    雪            看 看 看   
雪雪雪雪雪雪雪雪雪雪雪雪   看看  看  看看 
   雪     雪               
  雪雪雪雪雪雪雪雪     看看看看看看看看看 
 雪 雪     雪             看 
雪  雪雪雪雪雪雪雪      看看看看看看看看 
   雪     雪             看 
   雪雪雪雪雪雪雪     看看看看看看看看看 
                         
2011-6-10 08:05
0
雪    币: 386
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
好。。。。。。
2011-6-10 09:05
0
雪    币: 183
活跃值: (1193)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
收藏下

等待下文
2011-6-10 10:11
0
雪    币: 55
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
mark一下
2011-6-10 10:28
0
雪    币: 202
活跃值: (46)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
中间多加点注释就好了
2011-6-10 15:34
0
雪    币: 30050
活跃值: (2422)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
直接从文件格式验证也是可以的

function VerifySignature(Index: Integer): Integer;
var
  Signer: TElPKCS7Signer;
  Certificate: TElX509Certificate;
  Lookup: TElCertificateLookup;
  I, TagID: Integer;
  IncludedDigest, OriginalDigest, DecryptedDigest: string;
  MD5: TMessageDigest128;
  SHA1: TMessageDigest160;
  Data: string;
begin
  try
    // check for signature index validity
    Result := SB_AUTHENTICODE_ERROR_INVALID_INDEX;
    if (Index < 0) or (Index >= FMessage.SignedData.SignerCount) then
      Exit;
    Signer := FMessage.SignedData.Signers[Index];
    if Signer = nil then
      Exit;
    // attempt to find signer's certificate
    Result := SB_AUTHENTICODE_ERROR_NO_SIGNER_CERTIFICATE;
    Certificate := nil;
    Lookup := TElCertificateLookup.Create(nil);
    try
      Lookup.Criteria := [lcIssuer];
      Lookup.Options := [loExactMatch, loMatchAll];
      Lookup.IssuerRDN.Assign(Signer.Issuer.Issuer);
      I := FMessage.SignedData.Certificates.FindFirst(Lookup);
      while I >= 0 do
      begin
        if FMessage.SignedData.Certificates.Certificates[I].SerialNumber = Signer.Issuer.SerialNumber then
        begin
          Certificate := FMessage.SignedData.Certificates.Certificates[I];
          Break;
        end;
        I := FMessage.SignedData.Certificates.FindNext(Lookup);
      end;
    finally
      Lookup.Free;
    end;
    if (Certificate = nil) and (FCertStorage <> nil) then
    begin
      Lookup := TElCertificateLookup.Create(nil);
      try
        Lookup.Criteria := [lcIssuer];
        Lookup.Options := [loExactMatch, loMatchAll];
        Lookup.IssuerRDN.Assign(Signer.Issuer.Issuer);
        I := FCertStorage.FindFirst(Lookup);
        while I >= 0 do
        begin
          if FCertStorage.Certificates[I].SerialNumber = Signer.Issuer.SerialNumber then
          begin
            Certificate := FCertStorage.Certificates[I];
            Break;
          end;
          I := FCertStorage.FindNext(Lookup);
        end;
      finally
        Lookup.Free;
      end;
    end;
    if Certificate = nil then
      Exit;
    // calculate digest for authenticated attributes
    if Signer.DigestAlgorithm = SB_OID_MD5 then
    begin
      MD5 := HashMD5(Signer.AuthenticatedAttributesPlain);
      SetLength(OriginalDigest, SizeOf(MD5));
      Move(MD5, OriginalDigest[1], SizeOf(MD5));
    end
    else
      if Signer.DigestAlgorithm = SB_OID_SHA1 then
    begin
      SHA1 := HashSHA1(Signer.AuthenticatedAttributesPlain);
      SetLength(OriginalDigest, SizeOf(SHA1));
      Move(SHA1, OriginalDigest[1], SizeOf(SHA1));
    end
    else
    begin
      Result := SB_AUTHENTICODE_ERROR_INVALID_ALGORITHM;
      Exit;
    end;
    // check for authenticated attributes digest validity
    Result := SB_AUTHENTICODE_ERROR_INVALID_SIGNATURE;
    if (Signer.DigestEncryptionAlgorithm = SB_OID_RSAENCRYPTION) and
      (Certificate.PublicKeyAlgorithm = SB_CERT_ALGORITHM_ID_RSA_ENCRYPTION) then
    begin
      DecryptedDigest := DecryptRSA(Signer.EncryptedDigest, Certificate);
      if DecryptedDigest = '' then
        Exit;
      // compare the decrypted digest with calculated one
      if DecryptedDigest <> OriginalDigest then
        Exit;
    end
    else
      if (Signer.DigestEncryptionAlgorithm = SB_OID_DSA) and
      (Certificate.PublicKeyAlgorithm = SB_CERT_ALGORITHM_ID_DSA) then
    begin
      if not VerifyDSA(Signer.DigestAlgorithm, Signer.EncryptedDigest, OriginalDigest, Certificate) then
        Exit;
    end
    else
    begin
      Result := SB_AUTHENTICODE_ERROR_INVALID_ALGORITHM;
      Exit;
    end;
    // attempt to find included digest for authenticode data
    Result := SB_AUTHENTICODE_ERROR_SIGNATURE_CORRUPTED;
    IncludedDigest := '';
    if Signer.AuthenticatedAttributes.Count > 0 then
    begin
      for I := 0 to Signer.AuthenticatedAttributes.Count - 1 do
        if (Signer.AuthenticatedAttributes.Attributes[I] = SB_OID_MESSAGE_DIGEST) and
          (Signer.AuthenticatedAttributes.Values[I].Count > 0) then
        begin
          IncludedDigest := UnformatAttributeValue(Signer.AuthenticatedAttributes.Values[I].Strings[0], TagID);
          Break;
        end;
    end;
    if IncludedDigest = '' then
      Exit;
    // calculate digest for authenticode data
    Result := SB_AUTHENTICODE_ERROR_SIGNATURE_CORRUPTED;
    if Length(FMessage.SignedData.Content) < 2 then
      Exit;
    if Ord(FMessage.SignedData.Content[1]) <> $30 then
      Exit;
    case Ord(FMessage.SignedData.Content[2]) of
      $81: Data := Copy(FMessage.SignedData.Content, 4, MaxInt);
      $82: Data := Copy(FMessage.SignedData.Content, 5, MaxInt);
      $83: Data := Copy(FMessage.SignedData.Content, 6, MaxInt);
    else
      if Ord(FMessage.SignedData.Content[2]) < $81 then
        Data := Copy(FMessage.SignedData.Content, 3, MaxInt)
      else
        Exit;
    end;
    if Signer.DigestAlgorithm = SB_OID_MD5 then
    begin
      MD5 := HashMD5(Data);
      SetLength(OriginalDigest, SizeOf(MD5));
      Move(MD5, OriginalDigest[1], SizeOf(MD5));
    end
    else
      if Signer.DigestAlgorithm = SB_OID_SHA1 then
    begin
      SHA1 := HashSHA1(Data);
      SetLength(OriginalDigest, SizeOf(SHA1));
      Move(SHA1, OriginalDigest[1], SizeOf(SHA1));
    end
    else
    begin
      Result := SB_AUTHENTICODE_ERROR_INVALID_ALGORITHM;
      Exit;
    end;
    // check for authenticode data digest validity
    if OriginalDigest <> IncludedDigest then
    begin
      Result := SB_AUTHENTICODE_ERROR_INVALID_SIGNATURE;
      Exit;
    end;
    if (FActualDigest <> FDigest) then
      Result := SB_AUTHENTICODE_ERROR_INVALID_AUTHENTICODE
    else
      Result := SB_AUTHENTICODE_ERROR_SUCCESS;
  except
    Result := SB_AUTHENTICODE_ERROR_UNKNOWN;
  end;
end;
2011-6-11 18:27
0
雪    币: 30050
活跃值: (2422)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
签名也是一个鸟样:

:读取并HASH"MZ"
2:移动到$0000003C位置,并HASH前面的数据.
3:读入4字节到FHeaderOffset,判断FHeaderOffset + $A0是否大于文件大小.并HASH这FHeaderOffset.
4:移动到FHeaderOffset位置,并HASH前面的数据.
5:读入4字节到PESign,判断PESign 是否为 $00004550.并HASH这PESign.
6:
(1)保存当前流位置
(2)移动指针到当前位置+$14,并读入两字节.如果该内容为$020B,说明为64位PE,那么后面位置要加$10
(3)恢复流位置

7:移动到FHeaderOffset + $58位置,并HASH前面的数据.
8:FStream.Read(Checksum, 4)!!!注意,这里并没HASH
9:再次移动到SeekStream(FHeaderOffset + $98 + FDelta64bit)位置,并HASH前面的数据.
10:FStream.Read(SignatureOffset, 4)!!!注意,这里并没HASH
11:FStream.Read(SignatureSize, 4)!!!注意,这里并没HASH
12:根据SignatureOffset之类判断是否已经签名了.
13:SeekStream(FStream.Size)HASH余下的数据.
14:(FStream.Size and $F)判断整个文件大小是否能被16整除.不能则后面补零填充

(*
总结:
校验和的偏移位置(唯一一个不参与校验和计算的数据)
数字签名体的偏移位置
数字签名大小

*)
签名收尾:
var
  SignatureOffset, SignatureSize, Dummy: LongWord;

FStream.Position := FStream.Size;//移动到文件尾部
if FPadding <> '' then
   FStream.WriteBuffer(FPadding[1], Length(FPadding)); //补齐16字节

SignatureOffset := FStream.Position;//签名信息位置

SignatureSize := Length(S) + 8;//签名信息大小+sizeof(SignatureSize)+sizeof(Dummy)
FStream.WriteBuffer(SignatureSize, SizeOf(SignatureSize));//写入签名大小
CalcChecksum(FChecksum, @SignatureSize, SizeOf(SignatureSize));

Dummy := $00020200;
FStream.WriteBuffer(Dummy, SizeOf(Dummy));//写入Dummy
CalcChecksum(FChecksum, @Dummy, SizeOf(Dummy));

FStream.WriteBuffer(S[1], Length(S));//写入签名
CalcChecksum(FChecksum, @S[1], Length(S));

FStream.Position := FHeaderOffset + $98 +FDelta64bit;
FStream.WriteBuffer(SignatureOffset, SizeOf(SignatureOffset));//改写签名位置
CalcChecksum(FChecksum, @SignatureOffset, SizeOf(SignatureOffset));

FStream.WriteBuffer(SignatureSize, SizeOf(SignatureSize)); //改写签名大小
CalcChecksum(FChecksum, @SignatureSize, SizeOf(SignatureSize));

FStream.Position := FHeaderOffset + $58;
Dummy := FinalizeChecksum(FChecksum, FStream.Size);
FStream.WriteBuffer(Dummy, SizeOf(Dummy));//最后一个总数据校验
2011-6-11 18:28
0
雪    币: 30050
活跃值: (2422)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
仅调用系统的读写文件的API就可以了.逆的蛋疼.
2011-6-11 18:29
0
雪    币: 239
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
楼上强银~~
2011-6-11 23:08
0
雪    币: 58
活跃值: (1130)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
都是强人!!
2011-6-12 01:02
0
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
一个比一个厉害
2011-6-12 12:31
0
雪    币: 289
活跃值: (77)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
都是牛人!!!
2011-6-12 13:33
0
雪    币: 387
活跃值: (76)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
14
看了bestbird大牛,我感觉我没必要继续下去了
2011-6-13 02:03
0
雪    币: 300
活跃值: (179)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
15
人家说的和你的完全是2个不同的东西。也没看出来你应该受打击的部分,相信他发出东西来也不是为了打击你,为啥子不继续了呢,大家只是把各人掌握的东西共享出来,方便后来人。你发的不一定那天对某些人就有用了呢。别放弃,做自己想做的。
但PE数字签名本身而言,感觉这个还不错 http://www.ccgcn.com/bbs/redirect.php?tid=885&goto=lastpost
2011-6-13 08:58
0
雪    币: 123
活跃值: (50)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
强帖,占位学习
2011-6-14 08:10
0
雪    币: 7132
活跃值: (1140)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
好文章!好好学习下!
2011-6-16 21:42
0
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
18
好贴,向各位牛人学习!
2011-6-17 01:45
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
进来看看 呵呵!
2011-6-17 16:08
0
游客
登录 | 注册 方可回帖
返回
//