buuctf_Reverse_wp_1

easyre

查看程序基本信息,64bit 无壳

在这里插入图片描述
ida64打开一下

找到main函数直接F5发现了flag
在这里插入图片描述

reverse1

同样的步骤发现是64bit无壳程序

在这里插入图片描述

拖进ida64进去,找到main函数

在这里插入图片描述

逻辑就是让我们输入一个字符串,与它的Str2作对比,如果相等就是我们的flag,所以我们只要看一下Str2是什么,然后再做一下运算即可

在这里插入图片描述

reverse2

64bit elf文件

在这里插入图片描述

逻辑与上道题类似,也是通过找到原来的flag进行一定的运算
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

内涵的软件

查壳位数,是32位的

在这里插入图片描述

打开软件等待过后并没有出现flag

在这里插入图片描述

进入main函数发现了flag,v5变量

在这里插入图片描述

新年快乐[upx脱壳]

查一下32位有upx壳

在这里插入图片描述
用upx.exe -d xxx脱壳找到main函数

在这里插入图片描述

非常简单的逻辑,只要你输入的字符串和"HappyNewYear!"相等就行,也就是正确的flag

xor

查一下发现是64bitMACos文件
在这里插入图片描述

找到main函数,简单分析一下逻辑
在这里插入图片描述

找到global:FKWOXZUPFVMDGH按A转换字符串,然后shift+E导出数据
在这里插入图片描述

脚本处理一下,因为 0^0 = 0 0^1 = 1所以 0^a = a

a^b = c, b = a^c = a^(a^b) = 0^b = b

然后最后的逻辑就是让运算完的b中的元素分别等于global中的元素

也即b[1] = global[1]、b[2] = global[2]

又因为b[1] = b[1] ^ b[0] = global[1] ^ global[0]、b[2] = b[2] ^ b[1] = b[2] ^ b[1]^ b[0] = b[2] ^ global[1] = global[2] ^ global[1]

所以推下来b[ i ] = global[ i ] ^ global[ i - 1 ]

aFK =[
  0x66, 0x0A, 0x6B, 0x0C, 0x77, 0x26, 0x4F, 0x2E, 0x40, 0x11, 
  0x78, 0x0D, 0x5A, 0x3B, 0x55, 0x11, 0x70, 0x19, 0x46, 0x1F, 
  0x76, 0x22, 0x4D, 0x23, 0x44, 0x0E, 0x67, 0x06, 0x68, 0x0F, 
  0x47, 0x32, 0x4F, 0x00
]
flag = chr(aFK[0])
for i in range(1,len(aFK)-1):#第一个字符已经确定了,因为题目中下标从1开始的
    flag += chr(aFK[i] ^ aFK[i-1])
    
print(flag)

在这里插入图片描述

reverse3[逆算法]

查壳和位数,是一个32位

在这里插入图片描述
找到main函数,看一下逻辑

看到首先把destination数组清零,然后自己输入一个flag,用str变量接收,然后v4变量的值为sub_4110BE函数的返回值,最后strcpy到destination里面,然后在对destination的每个元素,分别加上对应的下标。使最后的结果为字符串e3nifIH9b_C@n@dH。

在这里插入图片描述

再看一下函数sub_4110BE函数

在这里插入图片描述
然后找到加密过程中有一个aAbcdefghijklmn的变量,它的值与base64编码的固定变量一致,那就确定这个函数是进行base64加密的了。

在这里插入图片描述

所以最后求flag的脚本如下:

import base64
flag = ''
res = ''
str1 = "e3nifIH9b_C@n@dH"
for i in range(len(str1)):
    res += chr(ord(str1[i]) - i)
print("now str1 is :", res)
flag = base64.b64decode(res)
print("flag is :", flag)

helloword[APK]

因为是一个apk安卓的一个安装包,所以我们用jadx打开看一下,并且找到main

在这里插入图片描述

直接看到了flag,所以这道题主要考我们会不会对安卓的安装包进行逆向

不一样的flag[maze]

是一个32位的程序

在这里插入图片描述

找到main函数

在这里插入图片描述

这道题一开始看了半天也没看出来,结果发现是一个maze迷宫题,因为以前没接触过所以有点犹豫了。

由所给的字符串可以看出迷宫是如下:

* 1 1 1 1

0 1 0 0 0

0 1 0 1 0

0 0 0 1 0

1 1 1 1 #

然后注意一下几个exit函数,也就是迷宫的规则。

第一个exit是判断输入错误的不用管

第二个是判断迷宫越界的,因为迷宫的每一行只有五个数,对应下标是0-4,所以一旦超过5,表明越界了。

第三个表明在走迷宫的时候不能碰到1,否则直接结束

所以由上面的那个迷宫我们可以判断出走的顺序为:

下下下右右上上右右下下下对应输入的数字为222441144222

所以flag就是flag{222441144222}

SimpleRev[大小端]

查看一下,是一个64bit的elf文件

在这里插入图片描述

看一下main函数,没有什么重要的东西,除了几个函数

在这里插入图片描述

其中Decry是进入游戏的关键函数,Exit函数只是退出函数,我们跟进一下Decry函数

其中重要的一段代码是如下:

在这里插入图片描述

其中join函数是字符串拼接函数

在这里插入图片描述

所以text的值为"killswodah"

key的值首先为key1 ADSFK

在这里插入图片描述

然后再拼接src变量 SLCDN

所以最后key的值为 ADSFKSLCDN 长度为10

然后进入循环10次,分别将key的每一个元素加32,即大写变小写

最后key就变为了 adsfkslcdn

在这里插入图片描述


分割线

上网首先查了一下资料,对于x64体系结构,通常使用小端序(Little Endian)来存储数据。在x64架构上运行的操作系统,例如Windows、Linux和macOS,都使用小端序作为默认的字节序。

在x64的ELF文件中,数据的存放方式也遵循小端序。最低有效字节存储在最低的内存地址,而最高有效字节存储在最高的内存地址。

但是ida打开以后,会将其自动转换为大端存放,所以在进行数据合并、转换等之类的操作时,要记得转换为正确的小端存放顺序(倒序存放)


所以更改一下上面的错误,key拼接完src以后转换小写的值是 adsfkndcls

同理text的值为 killshadow

然后最后通过输入的字符,分别给str2字符串赋值,最后看是否等于text如果等于则代表输入的字符串为正确的flag.

我们只能输入大写字母,因为代码只对大写字母进行了处理

所以写一下脚本

flag = ''
res = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
text = 'killshadow'
key = 'adsfkndcls'
for i in range(len(key)):
    ch = text[i]
    for j in res:
        if (ord(j) - 39 - ord(key[i % len(key)]) +97 ) % 26 +97 == ord(ch):
            flag += j
print("flag{"+flag+"}")

[GXYCTF2019]luck_guy

首先还是查一下有没有壳,发现是64位ELF文件

在这里插入图片描述

进入main函数看一下

在这里插入图片描述

可以看到代码的逻辑就是让我们输入flag然后进行比较。所以关键就是看一下patch_me这个函数的逻辑

在这里插入图片描述

然后发现只要a1模2等于1,那么就会直接结束,否则直接进函数get_flag函数

看一下其中的case1

在这里插入图片描述

首先把f1拼接到s中,然后再把f2拼接过去 ,最后输出flag,但是发现f2并没有进行初始化,然后看一下后面的case有没有进行初始化

发现是把一个字符串"icugof\x7F"复制到了s中,然后再把s拼接到f2

在这里插入图片描述

所以我们首先写一个脚本来看一下f2最后是什么

#include<stdio.h>
#include<string.h>

int main(){
	char str[12]="icug`of\x7F";
	int i;
	for (i = 0; i<=7; ++i)
	{
		if (i % 2 == 1)
		{
			str[i] -= 2;
		}
		else
		{
			--(str[i]);	
		}
	}
	puts(str);
	return 0;
} 

在这里插入图片描述

可以看出来是hate_me}

再加上前面f1的内容

在这里插入图片描述

所以最终结果是GXY{do_not_hate_me}

Java逆向解密

把下载好的class文件放进jd-gui中看看

在这里插入图片描述

着重看一下Encrypt函数再结合一下题目的描述,是找不到秘钥了,但是写了秘钥验证算法,也就是反推秘钥。

其中比较秘钥的代码为Resultlist.equals(KEYList),即比较KEYList与Resultlist的元素

其中KEYList为180, 136, 137, 147, 191, 137, 147, 191, 148, 136,
133, 191, 134, 140, 129, 135, 191, 65

写一个脚本跑一下

KEYList=[180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65]
flag = ''
for i in range(len(KEYList)):
    for j in range(32,126):
        if (j + 64 ^ 0x20) == KEYList[i]:
            flag += chr(j)
print(flag)

最终所得即为flag

[BJDCTF2020]JustRE[gui程序]

依旧是查一下,32位无壳

在这里插入图片描述

打开搜索main函数发现是一种创建GUI的函数WinMain,也就是图形化程序

在这里插入图片描述

就是一些初始化句柄的操作,然后就会想到最后的flag肯定是通过字符串的形式出来的,所以索性Shift+F12找一下字符串

找到了类似flag的变量,并且发现引用是在一个DialogFunc的函数中

在这里插入图片描述

于是得到flag,具体想看一下逻辑也不行,因为都是外部调用的函数extern

BJD{1999902069a45792d233ac}

刮开有奖[findcrypt插件]

32bit无壳

打开是个类似于刮刮乐的程序

在这里插入图片描述

ida32打开又是这种GUI程序

在这里插入图片描述

其中只有一个有用的函数DialogFunc跟进看看,找到了核心代码,只要让String的每一个元素对应与其相等即可

在这里插入图片描述

然后看到最后一个if比较,就能知道如果String的0-7与if条件符合的话,那么就是flag了

首先看一下String0,因为是由v7赋值的所以还要继续跟进一下sub_4010F0这个函数

sub_4010F0

在这里插入图片描述

还需要注意的地方:

  1. 这个v7其实是一个数组,因为地址是连续的(从v7[2] - v16)

在这里插入图片描述

所以归根结底,v7这个数组的值为"ZJSECaNH3ng"

  1. 代码里面的4*i其实就是我们每个数组的下标加一的意思,因为int占4字节,此时 i 乘以4后以后,正好是每一个元素存在数组的位置偏移,与上图对应。所以v6其实是等于a1[i]

在这里插入图片描述

直接自己重新写一下跑一下就行

#include<stdio.h>
int sub_4010F0(char *a1,int a2, int a3);
 
int main()
{
	char str[] = "ZJSECaNH3ng";
    sub_4010F0(str,0,10);
    puts(str);
    return 0;
}

int sub_4010F0(char *a1,int a2, int a3)
{
  int result; // eax
  int i; // esi
  int v5;
  int v6; // edx
  
  result = a3;
  for ( i = a2; i <= a3; a2 = i )
  {
    v5 = i;
    v6 = a1[i];
    if ( a2 < result && i < result )
    {
      do
      {
        if ( v6 > a1[result] )
        {
          if ( i >= result )
            break;
          ++i;
          a1[v5] = a1[result];
          if ( i >= result )
            break;
          while ( a1[i] <= v6 )
          {
            if ( ++i >= result )
              goto LABEL_13;
          }
          if ( i >= result )
            break;
          v5 = i;
          a1[result] = a1[i];
        }
        --result;
      }
      while ( i < result );
    }
LABEL_13:
    a1[result] = v6;
    sub_4010F0(a1, a2, i - 1);
    result = a3;
    ++i;
  }
  return result;
}

在这里插入图片描述

所以v7经过处理以后就是3CEHJNSZagn

然后接着看sub_401000函数因为他涉及到了v4、v5变量

sub_401000

乍一看这个函数比较复杂,也没有特别的提示,但是一旦注意到有个特殊的变量就知道是什么了

在这里插入图片描述

在这里插入图片描述

打开一看这明显和以前做过的base64加密要用的数据一样,所以断定这个函数就是base64加密的函数

或者用findcrypt插件直接搜索一下

在这里插入图片描述

所以这段代码的含义就是让经过base64加密的v4和v5分别等于ak1w,V1Ax,那我们直接base64解密一下即可

在这里插入图片描述

ak1w -> base64-decode -> jMp

V1Ax -> base64-decode -> WP1

再结合赋值方式(注意顺序!)可得String2-7

在这里插入图片描述

所以综上可以推出String的每一个元素分别如下

用脚本跑一下

String = ''
dic = '3CEHJNSZagn'
v18='WP1' 
String += chr(ord(dic[0]) + 34)
String += dic[4]
String += v18[0]
String += v18[1] 
String += v18[2]
v18 = 'jMp'
String += v18[0]
String += v18[1] 
String += v18[2]
print('flag{'+String+'}')

在这里插入图片描述

简单注册器[APK]

是一个简单的APK文件,直接jadx打开

在这里插入图片描述

然后找到关键的一个方法

在这里插入图片描述

但是看到逻辑

flag = (xx.length() == 32 && xx.charAt(31) == 'a' && xx.charAt(1) == 'b' && (xx.charAt(0) + xx.charAt(2)) + (-48) == 56) ? 0 : 0;

这句flag的值无论怎么样都是0,所以也就无法注册了,所以我们直接看flag=1的代码

直接用java跑一下

public class register{
    public static void main(String[] args) { 
        char[] x = "dd2940c04462b4dd7c450528835cca15".toCharArray();
        x[2] = (char) ((x[2] + x[3]) - 50);
        x[4] = (char) ((x[2] + x[5]) - 48);
        x[30] = (char) ((x[31] + x[9]) - 48);
        x[14] = (char) ((x[27] + x[28]) - 97);
        for (int i = 0; i < 16; i++) {
            char a = x[31 - i];
            x[31 - i] = x[i];
            x[i] = a;
        }
        String bbb = String.valueOf(x);
        System.out.println("flag{" + bbb + "}");

    }
}

[GWCTF 2019]pyre[python反汇编]

这一看题目就是对python进行逆向的,然后用uncompyle6进行反编译

或者随便找一个在线网站丢进去即可,随便一个网站都可以

https://tool.lu/pyc/

https://www.lddgo.net/string/pyc-compile-decompile

uncompyle6 attachment.pyc > attachment.py

在这里插入图片描述

在这里插入图片描述

因为input1是我们输入的flag所以要反推flag,首先从异或这里开始,因为题目中给的code是经过xor运算过后的,所以我们要知道最开始的code是什么样,又因为对于code[1]来说,original_code[1] = code[1] ^ original_code [2]

再加上对于字符异或实质上就是对其ascii值异或.

所以写个脚本跑一下

code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
flag = ''
# 将其都转换为ascii值
for i in range(len(code)):
    code[i] = ord(code[i])
print(code)
 #从最后一个到第一个,因为无论怎么运算最后一个元素都与最初的一致
for j in range (len(code)-2,-1,-1):
   code[j]  = code[j]  ^  code[j+1]
print (code)
#然后每个元素减去自己的下标
for k in range (len(code)):
    code[k] = code[k] - k
    if code[k] < 0:
        code[k] += 128
    flag += chr(code[k])
print(flag)

在这里插入图片描述

[ACTF新生赛2020]easyre

打开发现有upx壳脱一下壳

在这里插入图片描述

在这里插入图片描述

再检测一下发现无壳了,且为32位

在这里插入图片描述

定位关键函数

在这里插入图片描述

分析一下逻辑

首先第一个if告诉flag的前5位与最后一位分别是ACTF{}

那么就想到flag应该是 v6 + v5 + v10组成的,其中ACTF{}分别为v6、v10

所以现在只要求v5即可,然后由定义知道v5是一个共12字节的数组

在这里插入图片描述

然后到for循环,就是让 v4[i] == data_start[ v5[i] -1 ] 也即在

在这里插入图片描述

``

我们现在要求v5的具体值,比如当i=0时,data_start[ v5[0] - 1] = ‘*’

假如*在data_start的80索引下,那么此时v5[0] -1 = 80 v5[0] = 80 +1 =81

在这里插入图片描述

所以依此类推,写一个脚本

v4 = "*F'\"N,\"(I?+@"
#要把27h转换为单引号,且要转义一下 \'
data_start = '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(\'&%$# !"'
flag = ''
for ch in v4:
   flag += chr(data_start.find(ch) + 1)  #find方法会从字符串中找其子串首次出现的位置并返回其下标
print("flag{"+flag+"}")

在这里插入图片描述

findit[APK]

是一个apk文件,用jadx打开看一下有没有什么关键信息

找到MainActivity

在这里插入图片描述

提示我们一个flag就在这里,然后找到对应的算法,用java跑一下即可

public class wifi{
	public static void main(String[] args) {
		final char[] b = {'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'};
		 char[] y = new char[38];
		 		 for (int i2 = 0; i2 < 38; i2++) {
                        if ((b[i2] >= 'A' && b[i2] <= 'Z') || (b[i2] >= 'a' && b[i2] <= 'z')) {
                            y[i2] = (char) (b[i2] + 16);
                            if ((y[i2] > 'Z' && y[i2] < 'a') || y[i2] >= 'z') {
                                y[i2] = (char) (y[i2] - 26);
                            }
                        } else {
                            y[i2] = b[i2];
                        }
                    }
                    String n = String.valueOf(y);
                     System.out.println(n);
	}
}

[ACTF新生赛2020]rome

首先先查看一下是什么位数的程序,32位

在这里插入图片描述

定位到main函数中的func函数

在这里插入图片描述

发现这段代码的逻辑与上一道题一样,就是flag是由多个部分组合而成的,而且这一堆就是某个算法

在这里插入图片描述

第一个while是一个算法,第二个while是循环判断是否与v12一致,也即某个字符串经过第一个while的算法,得出的结果与v12字符串一致,相当于就是对于算法的逆向

写个脚本跑一下吧,直接暴力破解

v12 = "Qsw3sj_lz4_Ujw@l"
flag = ''
ascii_value=[]
for i in range(len(v12)):
    ascii_value.append(ord(v12[i])) #先都转换为ASCII值
print(ascii_value)
for j in range(len(v12)):  
	for ch in range(32,127):
        k  =  ch
        if 64 < ch <= 90:
            ch = (ch - 51) % 26 + 65
       	if 96 < ch <= 122:
            ch = (ch - 79) % 26 + 97
        if chr(ch) == v12[j]:
            flag += chr(k)
print("flag{"  +flag + "}")            

在这里插入图片描述

rsa[解析公钥,解密文件]

第一次见到这种加密题,也没有头绪,于是就直接看了一下wp,虽然知道这是ras加密。但是看到两个文件无法下手。

然后得知,从公钥文件,可以推出 e和n

因为 C = m ^ e mod n de = 1mod(φ(n))

直接从在线公钥解析网站中提取一下

https://www.ssleye.com/ssltool/pub_asysi.html

在这里插入图片描述

e = 65537
n = 86934482296048119190666062003494800588905656017203025617216654058378322103517

然后再找一个分解质因数的网站或者用yahu

那个数字王国分解的位数为多为70位,这个77位

http://www.factordb.com/index.php

在这里插入图片描述

p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463

有了p q n就可以直接解密了

上脚本

import gmpy2
# from Crypto.Util.number import *
import rsa

p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463
e = 65537
n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi) #或者用Crypto库也可以
# d = inverse(e,phi)
key = rsa.Private(n,e,int(d),p,q)
f = open("flag.enc", "rb+")
fr = f.read()
print(rsa.decrypt(fr,key))

[FlareOn4]login

这题下载附件以后,发现是个网页,里面有个js来判断你输入的是否是正确的flag

没想到里面出现了web…

我们看看js代码

 document.getElementById("prompt").onclick = function () {
                var flag = document.getElementById("flag").value;
                var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){
                    return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);
                });
                if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
                    alert("Correct flag!");
                } else {
                    alert("Incorrect flag, rot again");
                }
           }

(c <= “Z” ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26 ;
String.fromCharCode(c / c-26)

表达式1:如果c<=Z,即是大写字母A-Z(65-90) 那么该表达式值为90,如果c>z,也即c此时为小写字母a-z(97-122),此时表达式值为122

表达式2: c的ascii值加上13的值
如果 表达式1 >= 表达式2 那么返回 c+13,否则返回c-26

例如此时c = y,其ascii值为121,首先它大于Z的ascii值,则前一个表达式的值为122,后面表达式的值为121+13=134,又因为此时表达式1 < 表达式2,此时整体返回的是c的ascii值-26也即 134-26 = 108 也即字符l,这样做的目的相当于让其一直在字母表的顺序循环。

所以写一个脚本穷举一下即可

rotflag = "PyvragFvqrYbtvafNerRnfl@syner-ba.pbz"
ascii_value = []
for i in range(len(rotflag)):
    ascii_value.append(ord(rotflag[i])) #将其转换为对应的ascii值
flag = ''
for val in ascii_value: 
    if 65 <= val <= 90:
        val = val - 13 
        if val < 65:
            val = val + 26
        flag += chr(val)
    elif 97 <= val <= 122: 
        val = val - 13
        if val < 97 :
            val = val + 26
        flag += chr(val)
    else:
        flag += chr(val)
print("flag{"+flag+"}")

或者直接在线网站

http://www.hiencode.com/rot13.html

在这里插入图片描述

[WUSTCTF2020]level1

在这里插入图片描述

丢进ida64去

在这里插入图片描述

发现是打开一个叫flag的文件然后一行一行进行运算,最后的结果在output.txt文件

直接用脚本跑一下即可 (因为异或对于计算机来说要比除法好算的多吗,也可以那除法作为res的赋值)

numbers = [  
    198, 232, 816, 200, 1536, 300, 6144, 984, 51200, 570,  
    92160, 1200, 565248, 756, 1474560, 800, 6291456, 1782,  
    65536000  ]
flag = ''
for i in range(len(numbers)):
    res = numbers[i] >> (i+1)
    if (i+1)&1 == 1:
        flag +=chr(numbers[i]>>(i+1))
    else:
        flag +=chr(int(numbers[i]/(i+1)))
print(flag)

在这里插入图片描述

附一张先用除法的

在这里插入图片描述

[GUET-CTF2019]re[z3约束器]

64bit elf文件还有壳

在这里插入图片描述

拖一下壳

在这里插入图片描述

拖入ida64,通过查找字符串定位关键函数

在这里插入图片描述

再定位函数sub_4009AE,发现是一堆运算,让其对应相等即可得出flag

在这里插入图片描述

脚本跑一下,但是发现好麻烦啊,复制都懒得复制,于是直接从网上找了个用Z3约束器的方法

注:
有几个坑

1.没有a1[6],需要自己爆破,当时在页面提交用burp爆破即可

2.a1[16]与a1[17]的顺序相反

用之前先下载两个库

pip install z3
pip install z3-solver
from z3 import *

z = Solver()

a1 = [0]*32
for i in range(32):
    a1[i] = Int('a1['+str(i)+']')

z.add( 1629056 * a1[0] == 166163712 )
z.add( 6771600 * a1[1] == 731332800 )
z.add( 3682944 * a1[2] == 357245568 )
z.add( 10431000 * a1[3] == 1074393000 )
z.add( 3977328 * a1[4] == 489211344 )
z.add( 5138336 * a1[5] == 518971936 )
z.add( 7532250 * a1[7] == 406741500 )
z.add( 5551632 * a1[8] == 294236496 )
z.add( 3409728 * a1[9] == 177305856 )
z.add( 13013670 * a1[10] == 650683500 )
z.add( 6088797 * a1[11] == 298351053 )
z.add( 7884663 * a1[12] == 386348487 )
z.add( 8944053 * a1[13] == 438258597 )
z.add( 5198490 * a1[14] == 249527520 )
z.add( 4544518 * a1[15] == 445362764 )
z.add( 10115280 * a1[16] == 981182160 ) #我这里手动调换位置了
z.add( 3645600 * a1[17] == 174988800 )
z.add( 9667504 * a1[18] == 493042704 )
z.add( 5364450 * a1[19] == 257493600 )
z.add( 13464540 * a1[20] == 767478780 )
z.add( 5488432 * a1[21] == 312840624 )
z.add( 14479500 * a1[22] == 1404511500 )
z.add( 6451830 * a1[23] == 316139670 )
z.add( 6252576 * a1[24] == 619005024 )
z.add( 7763364 * a1[25] == 372641472 )
z.add( 7327320 * a1[26] == 373693320 )
z.add( 8741520 * a1[27] == 498266640 )
z.add( 8871876 * a1[28] == 452465676 )
z.add( 4086720 * a1[29] == 208422720 )
z.add( 9374400 * a1[30] == 515592000 )
z.add(5759124 * a1[31] == 719890500)

z.check()
print(z.model())

a1 = [0] * 32

a1[31] = 125 
a1[30] = 55  
a1[29] = 51  
a1[28] = 51  
a1[27] = 57  
a1[26] = 51  
a1[25] = 48  
a1[24] = 99  
a1[23] = 49  
a1[22] = 97  
a1[21] = 57  
a1[20] = 57  
a1[19] = 48  
a1[18] = 51  
a1[16] = 97  
a1[17] = 48  
a1[15] = 98  
a1[14] = 48  
a1[13] = 49  
a1[12] = 49  
a1[11] = 49  
a1[10] = 50  
a1[9] = 52   
a1[8] = 53   
a1[7] = 54   
a1[5] = 101  
a1[4] = 123  
a1[3] = 103  
a1[2] = 97   
a1[1] = 108  
a1[0] = 102

flag = ''

for i in range(len(a1)):
    flag += chr(a1[i])

print(flag)
#flag{e165421110ba03099a1c039337} 注意第6位后需要爆破位1(e后面)

在这里插入图片描述

CrackRTF[Resourcehacker]

查壳32位exe,定位到关键函数

在这里插入图片描述

需要注意两个函数

sub_40100A、sub_401019这两个分别对输入的密码进行了运算,至于是什么算法需要看函数

CryptCreateHash中的第二个参数其中0x8003u表示MD5、0x8004u表示SHA-1

sub_40100A -> SHA-1 sub_401019 -> MD5

知道这两个以后,可以用脚本跑一下密码因为第一个密码知道是6位

import hashlib
passwd1=''
Destination = "@DBApp"
sha1_hash = "6E32D0943418C2C33385BC35A1470250DD8923A9".lower()
md5_hash = "27019e688a4e62a649fd99cadaafdb4e"

for i in range(100001,1000000):
    passwd1 = str(i) + Destination
    h1 = hashlib.sha1(passwd1.encode("utf-8")).hexdigest()
    if h1 == sha1_hash:
       print(i)
       break

跑出密码是123321

第二个密码因为没有位数限制,所以就无法进行爆破了

法1:

但是找到了一个顶级网站里面可以爆破

https://www.somd5.com/

在这里插入图片描述

这样两个密码都知道了,打开程序输这两个密码就会得到一个名叫dpapp.rtf的文件

在这里插入图片描述

里面就有flag

法2:

只能转眼看最后一个匹配的函数了

在这里插入图片描述

这个函数的大体意思就是获取AAA的资源,最后生成一个rtf文件,我们首先要用Resource Hacker获取一下

在这里插入图片描述

然后再定位一下sub_401005函数

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这里涉及到了异或,且最后的内容返回到了a2也就是lpBuffer,再注意最后写到rtf文件中的指针也是lpBuffer,因为写入文件的指针就是lpBuffer,又因为写的文件是rtf文件,lpBuffer的最开始必然是RTF文件的文件头

RTF文件头 {\rtf1

正常逻辑是通过输入的密码与AAA的资源相异或,然后得到lpBuffer即新RTF文件,又因为异或的逆运算还是异或,所以用RTF文件与AAA资源相异或,同样能得到密码。即RTF头与AAA资源的前6位相异或

写一下脚本看看

AAA = [0x05, 0x7D, 0x41 ,0x15 ,0x26 ,0x01] 
ch = ''
passwd2=''
for i in AAA:
    ch += chr(int(i))
rtf = "{\\rtf1" #转义反斜杠
for j in range(6):
    passwd2 += (chr(ord(ch[j])^ord(rtf[j])))
print(passwd2)

在这里插入图片描述

[2019红帽杯]easyRE[fini段]

64位elf文件,拖进去看看,看到一堆函数,直接用Shift+F12来查找一下关键的字符串,定位you found me,应该是代表找到了flag

在这里插入图片描述

于是定位到函数sub_4009C6看一下逻辑,先看前一段

在这里插入图片描述

首先是一些赋值操作

v12 = Iodl>Qnb(ocy

v13 = y.i

v14 = d`3w}wek9{iy=~yL@EC

再加上v12、v13、v14的内存是连续的,所以可以将其看成一个数组

在这里插入图片描述

所以针对中间的异或可以写一个脚本得出v15的值,因为异或的逆运算仍然是异或

v15=''
v14 = "Iodl>Qnb(ocy\x7Fy.i\x7Fd`3w}wek9{iy=~yL@EC"
for i in range(len(v14)):
    v15 += chr( ord(v14[i]) ^ i )
print(v15)

得出一个感觉有用又感觉没用的东西,应该是一个提示,告诉我们flag的前四个字符是flag(感觉和没说一样呢0.0)

在这里插入图片描述

继续分析代码,通过findcrypt插件可以看出函数sub_400E44是一个base64加密,或者看到这一串字符串也同样能分辨出来

在这里插入图片描述

再接着往下看,看到这么一串长的base64加密

在这里插入图片描述

它经过了十次base64加密,最后一直解密的结果是

https://bbs.pediy.com/thread-254172.htm

在这里插入图片描述

额到这里其实我已经蒙了,因为得出来的网站打开也没有什么可以有用的信息,于是看了一下网上的wp发现还有一段关键代码,就在那一长串10次base64加密的后面

在这里插入图片描述

我们双击查看一下引用跳转到了一个sub_400D35的函数,定位关键函数

在这里插入图片描述

通过这个if语句的条件和上面的提示,可以得出v4与a5V变量依次异或的结果前四个字节是flag

所以可以先通过脚本来逆求出来v4,再通过v4依次与a5V循环异或得到flag

str1="flag"
v4=''
str2 = [ 0x40, 0x35, 0x20, 0x56, 0x5D, 0x18, 0x22, 0x45, 0x17, 0x2F, 
  0x24, 0x6E, 0x62, 0x3C, 0x27, 0x54, 0x48, 0x6C, 0x24, 0x6E, 
  0x72, 0x3C, 0x32, 0x45, 0x5B]
for i in range(4):
     v4 += chr (ord(str1[i])^str2[i])
print(v4)

在这里插入图片描述

然后跑flag

v4='&YA1'
str2 = [ 0x40, 0x35, 0x20, 0x56, 0x5D, 0x18, 0x22, 0x45, 0x17, 0x2F, 
  0x24, 0x6E, 0x62, 0x3C, 0x27, 0x54, 0x48, 0x6C, 0x24, 0x6E, 
  0x72, 0x3C, 0x32, 0x45, 0x5B]
flag = ''
for i in range(len(str2)):
    flag += chr(ord(v4[i%4]) ^ str2[i])
print(flag)

在这里插入图片描述

[MRCTF2020]Transform[算法异或]

64位无壳,定位关键代码

str的长度是32位

在这里插入图片描述

经过一系列运算

在这里插入图片描述

先看下dword_40F040

在这里插入图片描述

最终异或的结果

在这里插入图片描述

所以拿最终异或的结果与dword_40F040的低字节其实也就是本身(因为dword的大小就是32位,正好取低字节其实就是后16个字节,而题目所给的11h、16h都只占16位),相异或即可得到原来的byte_414040

在这里插入图片描述

此时再需要调整顺序即可得到flag

#转换为10进制
byte_414040 = ''
lowbyte = [9,10,15,23,7,24,12,6,1,16,3,17,32,29,11,30,27,22,4,13,19,20,21,2,25,5,31,8,18,26,28,14,8]
res = "gy{\x7Fu+<RSyW^]B{-*fB~LWyAk~e<\EobM" #最后异或的结果即byte_40F0E0
for i in range(32):
    byte_414040 += chr ( ord(res[i]) ^ lowbyte[i] )
print(byte_414040)
#然后调整顺序即可
flag = ''
index = [9,10,15,23,7,24,12,6,1,16,3,17,32,29,11,30,27,22,4,13,19,20,21,2,25,5,31,8,18,26,28,14,8]
for j in range(1,33):
    k = 0
    for inde in index:
        k+=1
        if inde == j:
            if k > 32: #如果索引越界,则直接跳出循环
                break
            flag += byte_414040[k-1]
print(flag)    

在这里插入图片描述

[WUSTCTF2020]level2

32位 elf文件 有upx壳

在这里插入图片描述

脱一下壳

在这里插入图片描述

然后拖入ida32 这题就结束了

从伪代码模式按 TAB 切换到汇编代码模式,就直接看到了flag

在这里插入图片描述

或者在伪代码模式中,shift+ F12 直接查找字符串

在这里插入图片描述

或者在查找字符串的选项下,按一下Address让他排序,第一个就是flag

在这里插入图片描述

[SUCTF2019]SignIn[RSA]

64 elf文件,定位到关键函数

在这里插入图片描述

分析一下逻辑

v8是输入的flag v7是最后要等于的字符串

然后v8会经过sub_96A函数来转换为v9

在这里插入图片描述

最后会经过一个类似加密的函数 __gmpz_powm,所以查一下这个函数

void __gmpz_init_set_str(mpz_t rop, const char *str, int base)

  • rop:一个指向mpz_t类型的指针,表示要初始化和设置的目标整数。
  • str:一个表示要设置的整数值的字符串。
  • base:一个整数,指定字符串中数字的基数(例如,10表示十进制,16表示十六进制)。

void __gmpz_powm(mpz_t rop, const mpz_t base, const mpz_t exp, const mpz_t mod)

该函数计算 (base^exp) mod mod

  • rop:一个指向 mpz_t 类型的指针,表示计算结果的目标整数。
  • base:一个表示底数的 GMP 整数。
  • exp: 一个表示指数的 GMP 整数。
  • mod:一个表示模数的 GMP 整数。

在这里插入图片描述

所以会首先给v7赋值,然后在将v9以16进制形式赋值给v6,紧接着给v4、v5以十进制形式赋值

最后计算 v6 ^ v5 mod v4,最后将结果更新到v6中,其实就是RSA算法

最后比较是不是与v7一致,如果一致代表正确

对于RSA算法中我们现在已知C、e以及n

首先求一下p、q用在线网站分解一下

p = 282164587459512124844245113950593348271

q = 366669102002966856876605669837014229419

e = 65537

用脚本写一下

from Crypto.Util.number import *

c = "ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35"
ciphertext = int(c, 16) # 将十六进制转换为10进制
#print(ciphertext)
#78510953323073667749065685964447569045476327122134491251061064910992472210485
p =  282164587459512124844245113950593348271
q =  366669102002966856876605669837014229419
e = 65537
n = p*q
phi = (p-1)*(q-1)
d = inverse(e,phi) #求出私钥d
#91646299298871237857836940212608056141193465208586711901499120163393577626813
#print(d)
m = pow(ciphertext,d,n)
print(m)
#185534734614696481020381637136165435809958101675798337848243069

现在反求出来v6其实也就是v9,这样就能通过sub_96A函数推出flag了

在这里插入图片描述

但是仔细一看这个sub_96A函数传入的两个参数,其实最后运算下来是一样的,只是用了十六进制表达

例如:a2=“73…” 此时a2[0] = ‘7’ a2[1] = ‘3’

此时 a0123456789abcd[ flag[0] >> 4 ] = 7

也即flag[0] >> 4 = 7 = 0000 0111 那么原本的flag[0]只需左移四位也即 0111 0000 = “7”(hex)

同理对于a2[1]

a0123456789abcd[ flag[1] & 0xF ] = 3 = 0000 0011 那么原本的flag[1] 也就是后四位(因为&0xF,表示取这个二进制数的后四位) 所以 flag[1] = 0000 0011 = “3” (hex)

所以以此类推,其实flag就等于我们所求的明文。

再写一个脚本跑一下

m = 185534734614696481020381637136165435809958101675798337848243069
#m_str = hex(m)[2:] #去掉0x
#print(m_str)
m_str = "73756374667b50776e5f405f68756e647265645f79656172737d"
byte_str = bytes.fromhex(m_str)
flag = byte_str.decode("utf-8")
print(flag)

[ACTF新生赛2020]usualCrypt[base64变表]

32位无壳,定位关键函数

在这里插入图片描述

首先定位到sub_401080函数

用findcrypt插件发现是一个base64加密,所以v5就是输入的v8经过base64加密得到的

再往下看,经过一个while循环可以判断出v5的具体内容

在这里插入图片描述
但是感觉上面那个变量有点浪费,而且这些代码也没有给出实质性的东西

索性就Shift+F12来查看字符串了

在这里插入图片描述

找到双击,但是并没有找到引用

在这里插入图片描述

这下就难住了,然后仔细一看base64那个加密函数不止单纯的一个base64加密,其中还有两个函数

在这里插入图片描述

先看这个函数就是判断让其大小写互换

然后就是最开始的函数sub_401000(),这里面对于base64加密的密钥互换了一下

在这里插入图片描述
在这里插入图片描述

所以写一个脚本跑一下,先大小写互换,然后用base64变表解密即可,所谓变表就是原本对于Base 64来说A就是对应的A,b就是对应的b,但通过变表以后,有一部分对应的内容不同了

#include<iostream> 
#include<cstdio> 
using namespace std;
int main()
{
	char aKlmnopqrstuvwx[60] = "KLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	char BASE64_table_40E0A0[12] = "ABCDEFGHIJ";
	char tmp;
	
	for (int i = 6 ; i < 15; i++)
	{
		tmp = aKlmnopqrstuvwx[i];
		aKlmnopqrstuvwx[i] =  BASE64_table_40E0A0[i];
		BASE64_table_40E0A0[i]	= tmp;
	}
	printf("%s\n", BASE64_table_40E0A0);
	return 0;	
}
//ABCDEFQRSTUVWXY其中从Q开始是交换后的

然后又因为40E0AA数组与40E0A0实质上地址是连续的是一个数组,所以最后将整个数组交换过后得到的新base64索引表为 ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/

然后再将所给密文转换完大小写即可直接用在线自定义编码的解密

http://web.chacuo.net/netbasex

在这里插入图片描述

或者直接用脚本将密文中的对应字符与新的索引表交换即可,例如对于密文中的GNX在索引表中分别对应QXN以此类推即可

import base64
base64_table = "ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/"
original_base64table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
original_dec = "ZmxhZ3tiGNXlXjHfaDTzN2FfK3LycRTpc2L9"
dec = ""
for i in range(len(original_dec)):
    dec += original_base64table[base64_table.find(original_dec[i])]
print(dec) # 此时得到的是标准base64索引表下的密文,直接解密即可
print(base64.b64decode(dec))

在这里插入图片描述

[HDCTF2019]Maze[花指令]

32位upx壳,脱一下壳

在这里插入图片描述

找到main函数但是不知道为什么无法F5进入,查了一下wp才发现,它代码call了一个不存在的地址

在这里插入图片描述

也就是俗称的花指令(junk code)

花指令(junk code)是一种专门用来迷惑反编译器的指令片段,这些指令片段不会影响程序的原有功能,但会使得反汇编器的结果出现偏差,从而使破解者分析失败。比较经典的花指令技巧有利用 jmpcallret 指令改变执行流,从而使得反汇编器解析出与运行时不相符的错误代码。

https://ctf-wiki.org/reverse/obfuscate/junk-code/

这也理解了为什么题目叫做 maze_behind_junk,所以就是要绕过花指令

我们直接用IDA打开,找到错误的花指令直接NOP掉,然后选中main函数按P键更新一下,就可以识别到main函数了
在这里插入图片描述

可以看到这个循环里面有wasd这也就提示我们是要上下左右走

在这里插入图片描述

结合一下迷宫总共有70个字符,所以就可以猜测是7 * 10 或者是 10 * 7

在这里插入图片描述

再结合到终点的信息此时坐标是(5,-4) 起点坐标是(7,0),变量asc_408078的初始值是7
在这里插入图片描述

在这里插入图片描述

所以最终猜测就是7行10列的一个迷宫,因为结合迷宫字符串中有+和F肯定一个代表起点一个代表终点,所以结合这些信息只能是如下

*******+**
******* **
****    **
**   *****
** **F****
**    ****
**********
//所以迷宫答案一目了然 ssaaasaassdddw 所以flag也出来了

[MRCTF2020]Xor[手撕main汇编]

32位有壳,脱壳以后定位main函数(但是其中没有直接F5出来,报错:401095: call analysis failed ),然后我直接定位到401095处的汇编代码F5进去伪代码,然后退出去再定位到main函数再按F5就进去了,也不知道是怎么回事

在这里插入图片描述

定位到关键函数

在这里插入图片描述

让输入的flag等于下列字符串

在这里插入图片描述

所以我们根据异或运算的逆运算仍然是异或就可以得到原本输入的字符串

写个脚本跑一下

str1 = 'MSAWB~FXZ:J:`tQJ"N@ bpdd}8g'
flag =''

for i in range(27):
    flag += chr( ord(str1[i]) ^ i)
print(flag)

在这里插入图片描述

也不知道为什么这么简单,有可能是刚开始进入main函数的时候会挖坑,但是我也不知道具体怎么弄的就进去了

网上看了wp以后,有人的方法和我一致,有的人就是直接看汇编了,不过逻辑比较简单

在这里插入图片描述

loc_4010B6:

让edx寄存器,即存着数组的首地址,依次指向下一个字符在这途中al一直不为0,也即ZF标志位一直为0,则jnz指令会一直跳转到自己这里从而形成了循环,直到遇到0字节(即数组的最后一个截止符),因为此时al为0,ZF=1,此时jnz指令不会跳转则执行下一段汇编代码,结束循环以后,edx值为7(因为多了一个字符串结束符’\0’)

这时edx减去ecx,因为前面有 lea ecx, [eax+1],相当于ecx此时是1,则sub edx, ecx则表示这个字符串的长度,最后比较是不是等于27,如果不等于则直接输出错误信息,如果等于则到了下面的关键代码

loc_4010D0

关键代码就是这个拿自己输入的flag byte_4212C0与byte_41EA08进行异或如果相等则跳转loc_4010FF

在这里插入图片描述

loc_4010FF

eax增加一直直到27,因为edx在上面被设置为27,如果eax到了27表明所有字符都进行了异或操作,也即表明结果一致,最后跳转到loc_4010D0,即输出Right!

在这里插入图片描述

[MRCTF2020]hello_world_go

是一个用go语言编写的64位elf文件
在这里插入图片描述

定位到main函数发现代码有点长

// main.main
void __cdecl main_main()
{
  __int64 v0; // rcx
  __int64 v1; // rax
  __int64 v2; // rax
  __int64 v3; // [rsp+20h] [rbp-90h]
  __int64 v4; // [rsp+58h] [rbp-58h]
  __int64 *v5; // [rsp+60h] [rbp-50h]
  _QWORD v6[2]; // [rsp+68h] [rbp-48h] BYREF
  __int64 v7[4]; // [rsp+78h] [rbp-38h] BYREF
  _QWORD v8[2]; // [rsp+98h] [rbp-18h] BYREF

  v5 = (__int64 *)runtime_newobject((__int64)&RTYPE_string);
  v8[0] = &RTYPE_string;
  v8[1] = &off_4EA530;
  fmt_Fprint(go_itab__ptr_os_File_comma_io_Writer, os_Stdout, v8, 1LL, 1LL);
  v7[2] = (__int64)&RTYPE__ptr_string;
  v7[3] = (__int64)v5;
  v3 = fmt_Fscanf(go_itab__ptr_os_File_comma_io_Reader, os_Stdin, &unk_4D07C9, 2LL);
  v0 = v5[1];
  v1 = *v5;
  if ( v0 != 24 )
    goto LABEL_2;
  v4 = *v5;
  if ( !runtime_memequal((__int64)&unk_4D3C58, v1, 24LL) )
  {
    v1 = v4;
    v0 = 24LL;
LABEL_2:
    runtime_cmpstring((__int64)&unk_4D3C58, 24LL, v1, v0, v3);
    if ( v3 >= 0 )
      v2 = 1LL;
    else
      v2 = -1LL;
    goto LABEL_4;
  }
  v2 = 0LL;
LABEL_4:
  if ( v2 )
  {
    v6[0] = &RTYPE_string;
    v6[1] = &off_4EA550;
    fmt_Fprintln(go_itab__ptr_os_File_comma_io_Writer, os_Stdout, v6, 1LL, 1LL);
  }
  else
  {
    v7[0] = (__int64)&RTYPE_string;
    v7[1] = (__int64)&off_4EA540;
    fmt_Fprintln(go_itab__ptr_os_File_comma_io_Writer, os_Stdout, v7, 1LL, 1LL);
  }
}

抱着试一试的态度去查一下字符串flag,发现直接查到了,或者随便点点变量发现26行的变量unk_4D3C58就是flag

在这里插入图片描述

到这里前32道题就写完,后续再写剩下的,依旧是抱着学习的态度来写

  • 23
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值