[toc]

链接静态库

1.自写

链接动态库

1
gcc -o httpc httpc.c -lssl -lcrypto

2.第三方

链接动态库

1.自写

链接静态库

1
gcc -o LinClient LinClient.c -static -lssl -lcrypto

2.第三方

打包程序

1.打包一个链接OpenSSl的程序

  1. 安装 OpenSSL

    1
    2
    sudo apt update
    sudo apt install openssl libssl-dev
  2. 编写代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    // LinClient.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <openssl/ssl.h>
    #include <openssl/err.h>

    #define BUFFER_SIZE 4096

    void send_request(SSL* ssl, const char* host, const char* path) {
    char request[BUFFER_SIZE];
    sprintf(request, "GET %s HTTP/1.1\r\n"
    "Host: %s\r\n"
    "Connection: close\r\n\r\n", path, host);
    SSL_write(ssl, request, strlen(request));
    }

    int main() {
    char response[BUFFER_SIZE];
    int bytes_received;

    // 初始化OpenSSL
    SSL_library_init();
    SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
    SSL* ssl = NULL;

    // 创建套接字
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
    perror("Could not create socket");
    return 1;
    }

    // 设置服务器信息
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(443); // HTTPS端口

    // 将主机名转换为IP地址
    struct hostent* host = gethostbyname("www.bilibili.com");
    if (host == NULL) {
    perror("Could not resolve hostname");
    close(sock);
    return 1;
    }
    memcpy(&server.sin_addr, host->h_addr, host->h_length);

    // 连接到服务器
    if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
    perror("Connect failed");
    close(sock);
    return 1;
    }

    // 初始化SSL连接
    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, sock);

    // 建立SSL连接
    if (SSL_connect(ssl) <= 0) {
    printf("SSL connect failed. Error Code: %ld\n", ERR_get_error());
    SSL_free(ssl);
    SSL_CTX_free(ctx);
    close(sock);
    return 1;
    }

    // 发送初始请求
    send_request(ssl, "www.bilibili.com", "/");

    // 接收响应并处理重定向
    while ((bytes_received = SSL_read(ssl, response, sizeof(response) - 1)) > 0) {
    response[bytes_received] = '\0'; // 添加字符串结束符
    printf("%s", response); // 打印响应

    // 检查是否有重定向
    if (strstr(response, "HTTP/1.1 301 Moved Permanently") ||
    strstr(response, "HTTP/1.1 302 Found")) {
    // 提取Location头
    char* location = strstr(response, "Location: ");
    if (location) {
    location += strlen("Location: ");
    char* end = strstr(location, "\r\n");
    if (end) {
    *end = '\0'; // 结束字符串
    printf("\nRedirecting to: %s\n", location);

    // 关闭当前SSL连接
    SSL_shutdown(ssl);
    SSL_free(ssl);
    close(sock);

    // 重新连接到新的URL
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
    perror("Could not create socket");
    SSL_CTX_free(ctx);
    return 1;
    }

    // 解析新的主机名
    char* new_host = location; // 这里假设Location是完整的URL
    char* path = strchr(new_host, '/'); // 找到路径
    if (path) {
    *path = '\0'; // 分离主机名
    path++; // 跳过'/'
    }

    // 连接到新的主机
    host = gethostbyname(new_host);
    if (host == NULL) {
    perror("Could not resolve hostname");
    close(sock);
    SSL_CTX_free(ctx);
    return 1;
    }
    memcpy(&server.sin_addr, host->h_addr, host->h_length);
    server.sin_port = htons(443); // HTTPS端口

    // 连接到新的服务器
    if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
    perror("Connect failed");
    close(sock);
    SSL_CTX_free(ctx);
    return 1;
    }

    // 初始化新的SSL连接
    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, sock);
    if (SSL_connect(ssl) <= 0) {
    printf("SSL connect failed. Error Code: %ld\n", ERR_get_error());
    SSL_free(ssl);
    SSL_CTX_free(ctx);
    close(sock);
    return 1;
    }

    // 发送请求到新的URL
    send_request(ssl, new_host, path);
    }
    }
    break; // 处理完重定向后退出循环
    }
    }

    // 关闭SSL连接和套接字
    SSL_shutdown(ssl);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
    close(sock);
    return 0;
    }
  3. 编译程序

    1
    gcc -o LinClient LinClient.c -lssl -lcrypto
  4. 查看程序依赖的动态库,手动复制到同一文件夹中

    1
    ldd LinClient
  5. 打包程序

2.使用make编译并且打包程序

  1. 编写makefile文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    # 定义变量
    CC = gcc
    CFLAGS = -Wall -g
    LDFLAGS = -lssl -lcrypto
    TARGET = LinClient
    SRC = LinClient.c
    OPENSSL_LIBS = /usr/lib/x86_64-linux-gnu/libssl.so /usr/lib/x86_64-linux-gnu/libcrypto.so
    PREFIX_BIN ?= /usr/local/bin# 可执行文件安装路径
    PREFIX_LIB ?= /usr/local/lib/LinClient# 库文件安装路径

    # 默认目标
    all: $(TARGET)

    # 编译目标
    $(TARGET): $(SRC)
    $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)

    # 安装目标
    install: $(TARGET)
    mkdir -p $(PREFIX_BIN) # 创建可执行文件目录(如果不存在)
    mkdir -p $(PREFIX_LIB) # 创建库文件目录(如果不存在)
    cp $(TARGET) $(PREFIX_BIN) # 将可执行文件复制到安装目录
    cp $(OPENSSL_LIBS) $(PREFIX_LIB) # 将库文件复制到安装目录

    # 卸载目标
    uninstall:
    @echo "Removing $(PREFIX_BIN)/$(TARGET)"
    rm -f "$(PREFIX_BIN)/$(TARGET)" # 从安装目录删除可执行文件
    @echo "Removing $(PREFIX_LIB)"
    rm -rf "$(PREFIX_LIB)" # 删除库文件夹与文件


    # 打包目标
    package: install
    tar -czvf LinClientPackage.tar.gz $(TARGET) $(OPENSSL_LIBS)

    # 清理目标
    clean:
    rm -f $(TARGET) LinClientPackage.tar.gz

    # 强制重新编译
    rebuild: clean all

    .PHONY: all install uninstall package clean rebuild

  2. 运行make命令编译

    1
    sudo make
  3. 运行命令打包程序与库

    1
    sudo make package
  4. 清理生成的文件

    1
    make clean
  5. 如果需要卸载程序

    1
    sudo make uninstall
  6. 如果需要将 LinClientPackage.tar.gz 文件复制到其他机器中

    1
    scp LinClientPackage.tar.gz kali@10.0.2.110:/home/kali/Downloads/
  7. 如果需要解压

    1
    mkdir -p LinClientPackage && tar -xzvf LinClientPackage.tar.gz -C LinClientPackage

3.使用cmake编译并打包程序

  1. 创建 CMakeLists.txt 文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    cmake_minimum_required(VERSION 3.10)

    # 项目名称和版本
    project(LinClient VERSION 1.0)

    # 查找 OpenSSL 库
    find_package(OpenSSL REQUIRED)

    # 添加可执行文件
    add_executable(LinClient LinClient.c)

    # 链接 OpenSSL 库
    target_link_libraries(LinClient OpenSSL::SSL OpenSSL::Crypto)

    # 安装目标
    install(TARGETS LinClient
    DESTINATION bin)

    # 安装动态库
    install(FILES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY}
    DESTINATION lib/LinClient)

    # 卸载目标
    if(NOT DEFINED CMAKE_INSTALL_PREFIX)
    set(CMAKE_INSTALL_PREFIX "/usr/local")
    endif()

    # 添加卸载目标
    set(UNINSTALL_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
    file(WRITE ${UNINSTALL_SCRIPT} "message(STATUS \"Uninstalling...\")\n")
    file(APPEND ${UNINSTALL_SCRIPT} "file(REMOVE \"${CMAKE_INSTALL_PREFIX}/bin/LinClient\")\n")
    file(APPEND ${UNINSTALL_SCRIPT} "file(REMOVE \"${CMAKE_INSTALL_PREFIX}/lib/LinClient/libssl.so\")\n")
    file(APPEND ${UNINSTALL_SCRIPT} "file(REMOVE \"${CMAKE_INSTALL_PREFIX}/lib/LinClient/libcrypto.so\")\n")
    file(APPEND ${UNINSTALL_SCRIPT} "file(REMOVE_RECURSE \"${CMAKE_INSTALL_PREFIX}/lib/LinClient\")\n") # 删除目录

    # 移除自动执行卸载脚本的命令
    # install(SCRIPT ${UNINSTALL_SCRIPT}) # 注释掉这一行

    # 打包目标
    set(CPACK_GENERATOR "TGZ")
    set(CPACK_PACKAGE_NAME "LinClient")
    set(CPACK_PACKAGE_VERSION "1.0")
    set(CPACK_PACKAGE_CONTACT "Your Name <your.email@example.com>")
    include(CPack)

    1. 编译和安装

      在终端中,执行以下命令来编译和安装程序:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      # 创建构建目录
      mkdir build
      cd build

      # 运行 CMake
      cmake ..

      # 编译程序
      make

      # 安装程序
      sudo make install
    2. 打包

      在构建目录中,运行以下命令来创建打包文件:

      1
      sudo cpack

      这将生成一个名为 LinClient-1.0-Linux.tar.gz 的压缩包

    3. 如果需要卸载程序

      1
      sudo cmake -P cmake_uninstall.cmake