逆向三个数按顺序输出

今天本来想做个有浮点,有开平方的一个小程序,但是OD看到fsqrt,fstw,fild,st0这些就崩溃了,而且明明已经开平方了然后又call了个C的sqrt函数,对我这个菜鸟还是有点难度了,先做个简单的吧
程序源码:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
void main()
{
 int x,y,z,t;
 scanf("%d%d%d",&x,&y,&z);
 if(x>y)
 {
  t=x;
  x=y;
  y=t;
 }
 if(x>z)
 {
  t=z;
  z=x;
  x=t;
 }
 if(y>z)
 {
  t=y;
  y=z;
  z=t;
 }
 printf("small to big: %d,%d,%d",x,y,z);
}

废话就不说了,直接来到main函数里面吧。
00401000  /$  83EC 0C       sub     esp, 0C                          ;  3个变量
00401003  |.  8D4424 08     lea     eax, dword ptr [esp+8]           ;  p3=eax
00401007  |.  8D4C24 04     lea     ecx, dword ptr [esp+4]           ;  p2=ecx
0040100B  |.  8D5424 00     lea     edx, dword ptr [esp]             ;  p1=edx
0040100F  |.  50            push    eax
00401010  |.  51            push    ecx
00401011  |.  52            push    edx
00401012  |.  68 48804000   push    00408048                         ;  ASCII "%d%d%d"
00401017  |.  E8 95000000   call    004010B1                         ;  scanf三个数 eax直接返回第3个数
0040101C  |.  8B5424 10     mov     edx, dword ptr [esp+10]          ;  edx=p1
00401020  |.  8B4C24 14     mov     ecx, dword ptr [esp+14]          ;  ecx=p2(ecx和edx则要自己取)类似的以&变量名为参数的函数应该都是用这样的方法来返回值的
00401024  |.  83C4 10       add     esp, 10                          ;  上面两条语句取完了数据再恢复4个变量的堆栈
00401027  |.  3BD1          cmp     edx, ecx                         ;  x y
00401029  |.  7E 0E         jle     short 00401039                   ;  x<y则跳转,即如果大于则要做一下交换了
0040102B  |.  8BC2          mov     eax, edx                         ;  z=x
0040102D  |.  8BD1          mov     edx, ecx                         ;  x=y
0040102F  |.  8BC8          mov     ecx, eax                         ;  y=z(上面三条即:x和y交换 但貌似把z给牺牲掉了)
00401031  |.  895424 00     mov     dword ptr [esp], edx
00401035  |.  894C24 04     mov     dword ptr [esp+4], ecx
00401039  |>  8B4424 08     mov     eax, dword ptr [esp+8]           ;  z又回来了~
0040103D  |.  56            push    esi                              ;  ??
0040103E  |.  3BD0          cmp     edx, eax                         ;  x z
00401040  |.  7E 0E         jle     short 00401050                   ;  小于跳转 大于的话 嘿嘿 做点交换
00401042  |.  8BF0          mov     esi, eax                         ;  t=z
00401044  |.  8BC2          mov     eax, edx                         ;  z=x
00401046  |.  8BD6          mov     edx, esi                         ;  x=t(z和x交换,t为中间变量)
00401048  |.  894424 0C     mov     dword ptr [esp+C], eax           ;  因为push了esi 所以第三个变量变成了esp+8+4=esp+c
0040104C  |.  895424 04     mov     dword ptr [esp+4], edx           ;  同理esp变成esp+4
00401050  |>  3BC8          cmp     ecx, eax                         ;  y z
00401052  |.  7E 0E         jle     short 00401062                   ;  老话题。。
00401054  |.  8BF1          mov     esi, ecx
00401056  |.  8BC8          mov     ecx, eax
00401058  |.  8BC6          mov     eax, esi                         ;  也是中间变量的方式来交换y和z,只是不知道为什么后两次交换用中间变量 第一次却用牺牲z的方法~~
0040105A  |.  894C24 08     mov     dword ptr [esp+8], ecx
0040105E  |.  894424 0C     mov     dword ptr [esp+C], eax
00401062  |>  50            push    eax
00401063  |.  51            push    ecx
00401064  |.  52            push    edx
00401065  |.  68 30804000   push    00408030                         ;  ASCII "small to big: %d,%d,%d"
0040106A  |.  E8 11000000   call    00401080
0040106F  |.  83C4 10       add     esp, 10
00401072  |.  5E            pop     esi
00401073  |.  83C4 0C       add     esp, 0C
00401076  \.  C3            retn
 
总结下,从上面代码可以看出 形如 函数名(&变量名)这样的函数返回值在反汇编中是在函数外直接从堆栈中取出到一些寄存器或者存储单元里面的,做了这个操作之后才把堆栈恢复平衡。其他的跳转,堆栈操作都比较熟悉了,ok。

顺便逆一个hello world级的程序
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
void main()
{
 printf("Hello World \n");
 printf("****\n");
 printf("*\n");
 printf("*\n");
 printf("****\n");
}
OD:
 00401000  /$  68 3C704000   push    0040703C                         ;  ASCII "Hello World ",LF
00401005  |.  E8 36000000   call    00401040
0040100A  |.  68 34704000   push    00407034                         ;  ASCII "****",LF
0040100F  |.  E8 2C000000   call    00401040
00401014  |.  68 30704000   push    00407030                         ;  ASCII "*",LF
00401019  |.  E8 22000000   call    00401040
0040101E  |.  68 30704000   push    00407030                         ;  ASCII "*",LF
00401023  |.  E8 18000000   call    00401040
00401028  |.  68 34704000   push    00407034                         ;  ASCII "****",LF
0040102D  |.  E8 0E000000   call    00401040
00401032  |.  83C4 14       add     esp, 14
00401035  \.  C3            retn
 
很失望是这样弱智的结果。。看到LF,应该是换行符吧,在数据窗口跟踪到LF对应0A。
有趣的是把0A填充成00 就是NULL了,C遇到这个NULL便以为已经结束了,所以没换行而最终输出了密密麻麻的星号。。。。。。。

### 实现按顺序输出任意整 在编程中,将一个任意正整的每一位字提取并按特定顺序(升序或降序)排列是一个常见的需求。以下是基于 C 语言的一种实现方案: #### 方法一:通过字符串操作实现 可以将整转换为字符串形式,逐位读取字符,并对其进行排序。 ```c #include <stdio.h> #include <string.h> void sortDigits(int num) { char str[50]; sprintf(str, "%d", num); // 将整转为字符串 int length = strlen(str); for (int i = 0; i < length - 1; ++i) { for (int j = i + 1; j < length; ++j) { if (str[i] > str[j]) { // 升序排列 char temp = str[i]; str[i] = str[j]; str[j] = temp; } } } printf("Sorted digits: %s\n", str); } int main() { int number; printf("Enter an integer: "); scanf("%d", &number); if (number >= 0) { sortDigits(number); } else { printf("Please input a positive integer.\n"); } return 0; } ``` 上述代码实现了将输入的正整按其各位字从小到大排序的功能[^1]。 --- #### 方法二:利用组存储每位字再排序 可以通过除法和取模运算提取整中的每一位字,存入组后再进行排序。 ```c #include <stdio.h> void sortDigitsUsingArray(int num) { int digits[10], count = 0; while (num != 0) { digits[count++] = num % 10; // 提取最低位字 num /= 10; // 去掉最低位 } // 对组中的字进行冒泡排序 for (int i = 0; i < count - 1; ++i) { for (int j = i + 1; j < count; ++j) { if (digits[i] > digits[j]) { // 升序排列 int temp = digits[i]; digits[i] = digits[j]; digits[j] = temp; } } } printf("Sorted digits:"); for (int i = 0; i < count; ++i) { printf(" %d", digits[i]); } printf("\n"); } int main() { int number; printf("Enter an integer: "); scanf("%d", &number); if (number >= 0) { sortDigitsUsingArray(number); } else { printf("Please input a positive integer.\n"); } return 0; } ``` 此方法同样能够完成对整各位置上的字进行升序排列的任务[^2]。 --- #### 方法:递归实现逆向输出 如果目标是从高到低依次打印出整的各个位,则可采用递归来解决问题。 ```c #include <stdio.h> void reversePrint(int n) { if (n < 10) { printf("%d ", n); } else { printf("%d ", n % 10); reversePrint(n / 10); } } int main() { int number; printf("Enter an integer: "); scanf("%d", &number); if (number >= 0) { reversePrint(number); } else { printf("Please input a positive integer.\n"); } return 0; } ``` 该程序展示了如何使用递归函来反向显示一个非负整的所有位[^3]。 --- ### 总结 以上种方法分别适用于不同的场景需求——无论是需要重新组合后的值还是仅需简单展示原列的不同部分都有对应的解决方案可供选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值