【问题标题】:Debug checksum algorithm written in x86 16-bit assembly用 x86 16 位程序集编写的调试校验和算法
【发布时间】:2020-03-21 06:59:32
【问题描述】:

我目前正在对一个软件进行逆向工程,该软件为给定的数据缓冲区计算 2 字节宽的校验和。该代码来自一个 16 位 DLL(NE 格式),并使用 Borland C++ 编译。我怀疑校验和是 CRC-16,其 poly 为 0x8408,但我没有机会计算相同的 CRC,所以我想知道实现是否是“CRC16 标准”。

这是组装实现:

crc_cal proc    far

var_4= word ptr -4
arg_0= word ptr  6
arg_2= dword ptr  8

mov ax, seg dseg37
inc bp
push    bp
mov bp, sp
push    ds
mov ds, ax
sub sp, 2
push    si
push    di
xor cx, cx
mov dx, 0FFFFh
mov [bp+var_4], 8408h

loc_42646:
les bx, [bp+arg_2]
add bx, cx
mov al, es:[bx]
xor al, dl
mov dl, al
inc cx
xor di, di
jmp short loc_42672

loc_42657:
mov si, dx
dec si
mov ax, si
shr ax, 1
mov si, ax
mov ax, dx
shr ax, 1
mov dx, ax
cmp si, dx
jnz short loc_42671
mov ax, dx
xor ax, [bp+var_4]
mov dx, ax

loc_42671:
inc di

loc_42672:
cmp di, 8
jb  short loc_42657
cmp cx, [bp+arg_0]
jb  short loc_42646
mov ax, dx
not ax
mov dx, ax
les bx, [bp+arg_2]
add bx, cx
mov es:[bx], dl
inc cx
mov ax, dx
shr ax, 8
mov dx, ax
les bx, [bp+arg_2]
add bx, cx
mov es:[bx], dl
inc cx
pop di
pop si
pop cx
pop ds
pop bp
dec bp
retf
crc_cal endp

还有一些带有相关 CRC(最后两个字节)的数据,由软件计算得出:

|                           DATA                           |Inc|CRC|
|----------------------------------------------------------|---|---|
00 00 00 00 00 00 01 ef f7 fe ef ff fd ef fb fa fd a2 aa 21 01 f4 e0
00 00 00 00 00 00 01 ef f7 fd ef ff fd fe fb fa fd a2 aa 21 02 f4 d1
00 00 00 00 00 00 01 f7 fe fd fd ff fd df ff fb fd a2 aa 21 03 f4 cd
00 00 00 00 00 00 01 f7 fe fe fd ff f7 ef ff fa fd a2 aa 21 04 f4 c2
00 00 00 00 00 00 01 ef f7 fe ef ff fe ef fb fa fd a2 aa 21 05 f4 db
00 00 00 00 00 00 01 ef f7 fe ef ff fd ef fb fa fd a2 aa 21 06 f4 db

【问题讨论】:

  • 没有标准的 CRC-16 实现,即使对于给定的多项式,也有多种实现方式可以为相同的输入给出不同的答案。见:en.wikipedia.org/wiki/Cyclic_redundancy_check#Specification
  • 那么,我的问题的答案是肯定的,你确实有一些输出已知的测试数据......那么你举个例子,看看我们是否可以做得更好?跨度>
  • 该实现似乎将最终结果与 0FFFFh 与 not ax 行进行异或。我对数学 CRC 知之甚少,无法确定它使用什么位或字节顺序。
  • 嗯,我已经运行了代码,但它似乎没有产生您显示的值。对于第一行,我得到e6 ef。此外,所有校验和都具有f4 非常可疑……我希望CRC会发生很大变化。你确定是20字节的数据+2字节的校验和,直接用这段代码计算的吗?哎呀,最后两行具有相同的校验和,即使它们在一个字节上有所不同?这将是一个疯狂的巧合。
  • 我组装它并在dosbox中运行它。它将数据大小和指向字节的远指针作为参数。它把校验和放在最后,就像你的例子一样。

标签: assembly reverse-engineering x86-16 checksum crc16


【解决方案1】:

显示的数据与 crc 不对应,如之前的答案所述:

Find used CRC-16 algorithm

代码是右移 CRC(在 dx 中)的过于复杂的实现,poly = 0x8408,初始值 = 0xffff,xor out = 0xffff。检查每行之后的接下来的 2 个字节,看看是否添加了 CRC。

带有 cmets 的问题代码。感谢 Ross Ridge 解释“inc bp”用于指示涉及远调用,以防堆栈需要回溯(末尾的“dec bp”用于撤消开头的“inc bp” )。

crc_cal proc    far

var_4   =       word ptr -4     ; used to store poly
arg_0   =       word ptr  6     ; number of bytes of data
arg_2   =       dword ptr 8     ; far pointer to data

        mov     ax, seg dseg37  ; for ds that is never used
        inc     bp              ; bp += 1, (bp&1 == far call indicator)
        push    bp              ; save bp+1
        mov     bp, sp          ; bp = sp, base for the equated offsets
        push    ds              ; save ds
        mov     ds, ax          ; ds = dseg37  (never used)
        sub     sp, 2           ; allocate space for poly (var_4)
        push    si              ; save si, di
        push    di
        xor     cx, cx          ; cx = offset to data
        mov     dx, 0FFFFh      ; dx = initial crc
        mov     [bp+var_4], 8408h ;store poly

loc_42646:
        les     bx, [bp+arg_2]  ; al = next byte of data
        add     bx, cx
        mov     al, es:[bx]
        xor     al, dl          ; crclo ^= data
        mov     dl, al
        inc     cx              ; increment offset to data
        xor     di, di          ; di = bit counter (0 to 7)
        jmp     short loc_42672

loc_42657:
        mov     si, dx          ; si = (crc-1)>>1
        dec     si              ;  if lsb was 0, then
        mov     ax, si          ;  si != dx later on
        shr     ax, 1
        mov     si, ax
        mov     ax, dx          ; dx = (crc)>>1
        shr     ax, 1
        mov     dx, ax
        cmp     si, dx          ; br if prior lsb of crc was 0
        jnz     short loc_42671
        mov     ax, dx          ; crc ^= 0x8408
        xor     ax, [bp+var_4]
        mov     dx, ax

loc_42671:
        inc     di              ; increment bit counter

loc_42672:
        cmp     di, 8           ; loop till byte done
        jb      short loc_42657
        cmp     cx, [bp+arg_0]  ; loop till all bytes done
        jb      short loc_42646
        mov     ax, dx          ; dx = ~ crc
        not     ax
        mov     dx, ax
        les     bx, [bp+arg_2]  ; append crc to data, lsbyte first
        add     bx, cx
        mov     es:[bx], dl
        inc     cx
        mov     ax, dx
        shr     ax, 8
        mov     dx, ax
        les     bx, [bp+arg_2]
        add     bx, cx
        mov     es:[bx], dl
        inc     cx              ; useless, cx gets overwritten below
        pop     di              ; restore di, si
        pop     si
        pop     cx              ; cx = poly
        pop     ds              ; restore ds, bp
        pop     bp
        dec     bp              ; bp -= 1 (undo inc bp from above)
        retf
crc_cal endp

【讨论】:

  • 它过于复杂,因为它编译的 C 代码,我猜基于表格的版本被认为太大了。
  • @RossRidge - 它是编译的 C 代码,它仍然过于复杂,而不是您看到的典型代码,例如 crc = (crc&1)? (crc>>1)^poly : (crc>>1); ,而是类似于 tmp = (crc-1)>>1; | crc = (crc >>1); | if (tmp == crc) crc = crc^poly;.
  • 如果您想知道 BP 的递增和递减的用途:devblogs.microsoft.com/oldnewthing/20110316-00/?p=11203
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-08
  • 1970-01-01
  • 1970-01-01
  • 2019-01-12
  • 1970-01-01
相关资源
最近更新 更多