同学写了一小段C代码,编译成Release版给大家玩.
在IDA中分析了一次, 记录一下.
.text:00401000 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00401000 _main proc near ; CODE XREF: start+AFp
.text:00401000
.text:00401000 var_4 = dword ptr -4
.text:00401000 argc = dword ptr 4
.text:00401000 argv = dword ptr 8
.text:00401000 envp = dword ptr 0Ch
.text:00401000
.text:00401000 push ecx
.text:00401001 push ebx
.text:00401002 push ebp
.text:00401003 push esi
.text:00401004 push edi
.text:00401005 ;save
.text:00401005 push 100 ; unsigned int
.text:00401007 pcAry100 = ebp ; new出来的char数组, 100个字节
.text:00401007 call ??2@YAPAXI@Z ; operator new(uint)
.text:0040100C ;new出来的数组清0
.text:0040100C mov pcAry100, eax
.text:0040100E mov ecx, 25
.text:00401013 xor eax, eax
.text:00401015 mov edi, pcAry100
.text:00401017 rep stosd
.text:00401019 ;开始用数组
.text:00401019 piAry_25_cur = ebx
.text:00401019 iIndex = eax
.text:00401019 mov iIndex, 1
.text:0040101E add esp, 4 ; new 函数的平栈, 流水线优化时放在这的
.text:00401021 sub iIndex, pcAry100
.text:00401023 mov piAry_25_cur, pcAry100
.text:00401025 mov edi, 3 ; 筛法,从3开始
.text:0040102A mov [esp+10h], iIndex ; 保存数组首地址取反+1,加上数组首地址, 作为位置索引
.text:0040102A ; 等于是一个间接的位置索引,加上数组首地址后,就是位置索引
.text:0040102E
.text:0040102E L_JUDGE_PRIME: ; CODE XREF: _main+6Cj
.text:0040102E cmp byte ptr [piAry_25_cur], 0
.text:00401031 jnz short L_GET_NEXT_ODD_NUMBER ; char数组初始化时,全部初始化为0,假设全部为质数
.text:00401031 ; 标记为1时, 说明不是质数, 已经判断过.
.text:00401033 lea ecx, [iIndex+piAry_25_cur]
.text:00401036 cmp ecx, 100 ; 本程序判断的是0~99之间,从3开始的奇数是否为质数
.text:00401036 ; 如果 i >= 100, 过了char数组的上界, 不判断了
.text:00401039 jge short L_GET_NEXT_ODD_NUMBER
.text:0040103B ;数组当前值为0, 且Index < 100
.text:0040103B lea esi, [piAry_25_cur+1] ; ary next position
.text:0040103E lea ecx, [edi+2] ; 偶数不是质数,只有奇数才有可能是质数.从3开始,判断每次加2的数是否为质数
.text:00401041 用奇数试除来确定质数
.text:00401041
.text:00401041 L_TEST_DIV_ODD: ; CODE XREF: _main+5Cj
.text:00401041 cmp byte ptr [esi], 1
.text:00401044 jz short L_NEED_NOT_JUDGE ; 为1时,说明已经判断过,不是质数
.text:00401046 mov iIndex, ecx
.text:00401048 cdq
.text:00401049 idiv edi ; eax / edi => eax:edx => 商:余数
.text:0040104B test edx, edx
.text:0040104D jnz short L_NEED_NOT_JUDGE ; 如果非0, 说明是不是能整除的数,有可能是质数,去试除下一个奇数
.text:0040104F mov byte ptr [esi], 1 ; 余数为0, 被整除了, 不是质数
.text:0040104F ; 将筛法数组中,能被当前奇数整除的奇数全部标记为非质数
.text:00401052
.text:00401052 L_NEED_NOT_JUDGE: ; CODE XREF: _main+44j
.text:00401052 ; _main+4Dj
.text:00401052 add ecx, 2
.text:00401055 inc esi
.text:00401056 cmp ecx, 203 ; 这个最大奇数怎么确定的? 如果不是公式搞出来的, 就没意义了.
.text:0040105C jl short L_TEST_DIV_ODD
.text:0040105E mov iIndex, [esp+10h] ; 恢复数组索引
.text:00401062 ;计算下一个位置
.text:00401062
.text:00401062 L_GET_NEXT_ODD_NUMBER: ; CODE XREF: _main+31j
.text:00401062 ; _main+39j
.text:00401062 add edi, 2
.text:00401065 inc piAry_25_cur
.text:00401066 cmp edi, 203
.text:0040106C jl short L_JUDGE_PRIME
.text:0040106E ;开始打印了
.text:0040106E iIndex1 = edi
.text:0040106E xor iIndex1, iIndex1
.text:00401070 mov esi, 3 ; 偶数位置肯定不是质数, 从3开始
.text:00401075
.text:00401075 L_PRINT_PRIME: ; CODE XREF: _main+93j
.text:00401075 cmp byte ptr [iIndex1+pcAry100], 0 ; 用的筛法么?
.text:00401075 ; 该数组元素为1,不是质数
.text:00401075 ; 该数组元素为0,是质数
.text:00401075 ; 作者定义了2个宏
.text:00401079 jnz short L_FIND_NEXT_PRIME ; 偶数位置肯定不是质数, 从3开始,每次+2的数组元素做质数判断
.text:0040107B push esi
.text:0040107C push offset Format ; "%d\n"
.text:00401081 call _printf ; 打印质数
.text:00401086 add esp, 8
.text:00401089
.text:00401089 L_FIND_NEXT_PRIME: ; CODE XREF: _main+79j
.text:00401089 add esi, 2 ; 偶数位置肯定不是质数, 从3开始,每次+2的数组元素做质数判断
.text:0040108C inc iIndex1
.text:0040108D cmp esi, 203 ; 最大打印的质数为203
.text:00401093 jl short L_PRINT_PRIME ; 用的筛法么?
.text:00401093 ; 该数组元素为1,不是质数
.text:00401093 ; 该数组元素为0,是质数
.text:00401093 ; 作者定义了2个宏
.text:00401095 ;释放资源
.text:00401095 push pcAry100 ; lpMem
.text:00401096 call ??3@YAXPAX@Z ; operator delete(void *)
.text:0040109B add esp, 4
.text:0040109E ;restore
.text:0040109E pop edi
.text:0040109F pop esi
.text:004010A0 pop ebp
.text:004010A1 pop ebx
.text:004010A2 pop ecx
.text:004010A3 retn
.text:004010A3 _main endp
如果逆向的结果可以被正确理解&&可以自由调试, 可以整理的可读性好些.
如果算法不可理解,逆向结果整理一下就可以了.
// hw.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include
#include
#include
#define MAX_PRIME 203
#define SECOND_ODD 3 // 第2个奇数, 质数从3开始求的,如果要打印3之前的质数,直接打印,不用算了
#define TWO 2 // 一次加2个, 从 SECOND_ODD 开始
int main(int argc, char* argv[])
{
int iIndexOffset = 0; ///< 当前位置的间接索引
int iTemp = 0;
char* pcPrime = new char[100]; ///< 存放的是奇数位置索引
ZeroMemory(pcPrime, 100); ///< 假设初始都是质数
char* pcPrimeCur = pcPrime;
char* pcPrimeNext = NULL; ///< pcPrimeCur的下一个位置
iIndexOffset = ~(int)pcPrime + 1;
// 筛法求质数
for (int iDivisor = SECOND_ODD;
iDivisor < MAX_PRIME;
iDivisor += TWO, pcPrimeCur++)
{
if ((0 == *pcPrimeCur) && (((int)pcPrimeCur + iIndexOffset) < 100)) {
for (pcPrimeNext = pcPrimeCur + 1, iTemp = iDivisor + TWO;
iTemp < MAX_PRIME;
iTemp += TWO, pcPrimeNext++)
{
if (1 != *pcPrimeNext) {
if (0 == (iTemp % iDivisor)) {
// 被整除,已经排除是质数
*pcPrimeNext = 1;
}
}
}
}
}
// 打印质数
for (iIndexOffset = 0, iTemp = SECOND_ODD;
iTemp < MAX_PRIME, iIndexOffset < 100;
iIndexOffset++, iTemp += TWO)
{
if (0 == *(pcPrime + iIndexOffset)) {
printf("%d\n", iTemp);
}
}
if (NULL != pcPrime) {
delete pcPrime;
pcPrime = NULL;
}
system("pause");
return 0;
}