看似杂乱无章的组装

逆向工程 拆卸 x86
2021-07-05 07:42:24

我已经将一个旧的 DOS 程序反汇编成汇编,我正在尝试找出一个函数调用。这是 ASM:

seg000:373C ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
seg000:373C
seg000:373C
seg000:373C sub_373C        proc far                ; CODE XREF: sub_72C6+16BP
seg000:373C                                         ; sub_72C6+18FP ...
seg000:373C                 push    si              ; Temp. store si on stack so we can restore it later
seg000:373D                 xchg    ax, si
seg000:373E                 xchg    ax, dx
seg000:373F                 test    ax, ax
seg000:3741                 jz      short loc_3745
seg000:3743                 mul     bx              ; Multiply b by a IIF a is non-zero
seg000:3745
seg000:3745 loc_3745:                               ; CODE XREF: sub_373C+5j
seg000:3745                 jcxz    short loc_374C
seg000:3747                 xchg    ax, cx
seg000:3748                 mul     si
seg000:374A                 add     ax, cx
seg000:374C
seg000:374C loc_374C:                               ; CODE XREF: sub_373C:loc_3745j
seg000:374C                 xchg    ax, si
seg000:374D                 mul     bx
seg000:374F                 add     dx, si
seg000:3751                 pop     si              ; Restore old si
seg000:3752                 retf
seg000:3752 sub_373C        endp

坦率地说,它似乎让我周围的寄存器乱七八糟。我最好的猜测是它是某种原始的伪随机数生成器。任何人都可以确认这一点,如果没有,请告诉我它的实际用途是什么?

编辑:
我试过干运行代码,据我所知,以下是寄存器的最终结果(谁能确认我做对了,并告诉我它可能在做什么有用的数学函数?):

ax: ( ax * bx )
bx: bx
cx: cx
dx: ax + ( (bx * dx) + (ax * cx) )
2个回答

这似乎是在 16 位架构上实现的 32 位乘法。

输入数字是dx:axcx:bx,结果是dx:ax

xchg奇妆的代码混淆,但如果你玩它通过你注意到它做了一堆与输入数字的高和低16位的一个单独的乘法。

在这一点上,我有一种预感,它可能是 32 位乘法,所以我试图了解输入数字拆分和结果拆分的情况,并从相反的方向解决问题。

假设上述输入,可以推导出以下公式:

dx:ax = (dx << 16) + ax
cx:bx = (cx << 16) + bx

然后只是多个它们:

(dx:ax * cx:bx) = (dx << 16)*(cx << 16)  + (dx << 16)*bx + ax*(cx << 16) + ax*bx

如果你看一看,我们这里增加了 3 个而不是两个。原因是高位相乘会溢出 32 位,所以第一个乘数在上面的代码中被默默丢弃。

这让我们

(dx:ax * cx:bx) = (dx << 16)*bx + ax*(cx << 16) + ax*bx

现在,如果您 每种情况考虑移位和乘法,因为移位只不过是乘以 2 的幂,它们交换意味着这等效于:

(dx:ax * cx:bx) = (dx*bx << 16) + (ax*cx << 16) + ax*bx

然后我们可以轻松地将其拆分回 16 位:

dx = dx*bx + ax*cx
ax = ax*bx

有了它,两个 32 位数字相乘的结果作为 16 位字给出。

这似乎与代码正在执行的操作相匹配(对于 bx cx 交换可能是安全的,您可能需要仔细研究一下),所以它似乎只是乘以数字。

编辑:有了这些知识以及 Igor 对您之前问题的回答,我找到了这个源代码:

https://github.com/gandrewstone/GameMaker/blob/master/tools/BORLANDC/CRTL/CLIB/F_LXMUL.ASM

这证实了这一发现。

看起来代码专门生成这些输出:

ax: (ax * bx)
dx: (bx * dx + ax * cx)

这是在mul指令永远不会有足够大的操作数设置dx为非零值的假设下。(如果这是真的,那么它seg000:374F是 anadd而不仅仅是xchg.似乎有点奇怪。)

也许它正在计算两个分数的相加?

dx   cx   (bx * dx + ax * cx)
-- + -- = -------------------
ax   bx        (ax * bx)