From 8ae3dd720abfb18a193df3a356b10c214ab40de0 Mon Sep 17 00:00:00 2001 From: "QCQCQC@Ubuntu" <1220204124@zust.edu.cn> Date: Tue, 8 Apr 2025 10:17:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8B=86=E4=B8=BA=E5=A4=9A=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=BB=93=E6=9E=84=EF=BC=8C=E8=A7=84=E8=8C=83=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 4 +- Makefile | 22 +- build/config.o | Bin 0 -> 5136 bytes build/debug.o | Bin 0 -> 936 bytes build/execve_interceptor.o | Bin 0 -> 4312 bytes build/init_cleanup.o | Bin 0 -> 2000 bytes build/intercept.so | Bin 0 -> 26312 bytes build/logging.o | Bin 0 -> 4736 bytes build/rules.o | Bin 0 -> 1544 bytes build/utils.o | Bin 0 -> 2376 bytes execve_intercept.c | 515 ------------------------------------- intercept.so | Bin 30672 -> 0 bytes src/config.c | 144 +++++++++++ src/config.h | 10 + src/debug.c | 11 + src/debug.h | 15 ++ src/exec_hook.h | 40 +++ src/execve_interceptor.c | 106 ++++++++ src/execve_interceptor.h | 14 + src/init_cleanup.c | 43 ++++ src/init_cleanup.h | 7 + src/logging.c | 100 +++++++ src/logging.h | 7 + src/rules.c | 23 ++ src/rules.h | 8 + src/struct.h | 22 ++ src/utils.c | 34 +++ src/utils.h | 7 + test_bash.sh | 2 +- 29 files changed, 611 insertions(+), 523 deletions(-) create mode 100644 build/config.o create mode 100644 build/debug.o create mode 100644 build/execve_interceptor.o create mode 100644 build/init_cleanup.o create mode 100755 build/intercept.so create mode 100644 build/logging.o create mode 100644 build/rules.o create mode 100644 build/utils.o delete mode 100644 execve_intercept.c delete mode 100755 intercept.so create mode 100644 src/config.c create mode 100644 src/config.h create mode 100644 src/debug.c create mode 100644 src/debug.h create mode 100644 src/exec_hook.h create mode 100644 src/execve_interceptor.c create mode 100644 src/execve_interceptor.h create mode 100644 src/init_cleanup.c create mode 100644 src/init_cleanup.h create mode 100644 src/logging.c create mode 100644 src/logging.h create mode 100644 src/rules.c create mode 100644 src/rules.h create mode 100644 src/struct.h create mode 100644 src/utils.c create mode 100644 src/utils.h diff --git a/.vscode/settings.json b/.vscode/settings.json index e8731cb..3fc51a4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,8 @@ "*.json": "jsonc", "string.h": "c", "shm.h": "c", - "unistd.h": "c" + "unistd.h": "c", + "logging.h": "c", + "fcntl.h": "c" } } \ No newline at end of file diff --git a/Makefile b/Makefile index da84008..940fef5 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,32 @@ CC = gcc CFLAGS = -shared -fPIC -Wall -Wextra -Werror -O2 -fno-strict-aliasing -fPIC -fno-omit-frame-pointer -fno-stack-protector -Wl,-z,relro,-z,now LDFLAGS = -ldl -ljson-c -TARGET = intercept.so -SRC = execve_intercept.c +TARGET_NAME = intercept.so +BUILD_DIR = build +SRC_DIR = src +SRC = $(wildcard $(SRC_DIR)/*.c) +OBJ = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SRC)) +TARGET = $(BUILD_DIR)/$(TARGET_NAME) # 如果需要开启 debug,只需执行 make DEBUG=1 ifeq ($(DEBUG),1) - CFLAGS += -DDEBUG + CFLAGS += -DDEBUG -g # Add -g for debugging symbols endif all: $(TARGET) -$(TARGET): $(SRC) +$(BUILD_DIR)/$(TARGET_NAME): $(OBJ) + @mkdir -p $(BUILD_DIR) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + @mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) -c $< -o $@ + clean: - rm -f $(TARGET) + rm -rf $(BUILD_DIR) debug: $(MAKE) DEBUG=1 - \ No newline at end of file + +rebuild: clean all \ No newline at end of file diff --git a/build/config.o b/build/config.o new file mode 100644 index 0000000000000000000000000000000000000000..d6eed6afbb75be153b7d403bc4141537c380ac93 GIT binary patch literal 5136 zcmb`Ke{3AZ701UvliCSqAPM0|@JTUMT9J(}7_b{aK5Qpzx+KuVBnZrAZSUDf?w9WN zzy>LCI1XiVT(BBNLKS}?S|p?@D*RE^xJrAHO`IT*B2fRRR8>_A0+Xt!suV?ma(&;~ z8GCNy{Rj0)x3lw^_ujnu^=9wbfUu8v8mV-K;Fnxu?9*0%EA%U^q0h~2>c6T0)- zknVmSJs5o=Iut#y-zdM)!NS+7`tg4i4ib#MY5c;2NC^0&h%pF>v?>7^$0IJcQR8}4^{say1Rc_!4} zPmz|+!I7}yZH22%`HJ8i%#D$Uo=c&X=5-h1(N-qkk)kt@1ep5(0j z4)=FzYscApw*H=xmS4q zhWnKmC`}yAsespfqt{Dk5CM%`G;lrgg-G;b)!F2M@{5ggRq9%I&r1yq0~)sqjo&v? z6m#vhN_@zwQU{c(4J)1&3m6B4V!?2I5n_9^R;yKt36sP-quCA>uY6Yv=V)Vz89xn| zWO(Wm(iw<+rk4vHw4{c6_7J&v)cu_1#M>u)-rawBL!cQiR-BEz!bgi~5d$79d{8%d zd;#a8zvtKRf2?AZxWAE-eNILuAg^ayfZ+@ zh7QFHhF|_|hLm~lv?*`XOB=medGvz5tHoKXyDhWSJG(f4F;baV+|9`Ix1T({4o{^m z+_JEXIa?zY>2a-I8oqjQJ~o3gQn|PUCB*&5o=#enU(urc0b8Ey(_DC`!0j$nt4<>F zNyOV&y4#=^u2!8a#d{d*qMT)#y{&qw;XFcUSe)KK&UheRzsutnp7qkutnRjn0GFO2 zXEAZUhOY{@GRSG}N9jsmq;MHq+D2A8oMdK)J!y}c6Y2Dk9i!<~EI!V`bGDhyC+wW| zY%ZN*cFGz_*kg<%Hkuq`&Q!)`$=o=zvg0|Hn@En^PB>=8p+z-oxx)7J_5CEgZD=H) za`NFwMC;Nzw@3248acXir`Fl^BY_!fq`;6WG5S4whZrTd3K)-=$_?~`)V=UCRyWyJ zcl)|EYiDR_w-LL8w=i}Wlm~8Td!@c_eRKS^hEt8@rdOK_YwDkBA?^OwFg5E!w;v_f zePn%e2JO+-C_Nt_oDe!Zp-X>ypn}8C#u#x>6`QSQf zSmoxx!SrUMR^2=I&9#tf-uyJPwZ4{HdA*r#oLae4@SAEe+bZ}iK8|^2teM^JNhFlb4rI@+L*!OVMF!$}=y?@|*Xka-f8&8chDpKf1j2q)Klj*T|ERGcGSPn~A zIcFJ}PCRMX%v3yPrfhr6OUUFHd6_!&(lg80*=#!NEj#NHCFNV5Yrmzt0n#Hla`1Zk zNxolj=%Y>YxZq&OHInBQj@%_V?pz4;aSkMZ50C`@aTiGbJ|KzT|3@C?T=oB{;6J7k zIZpcdhoXP8!ewHHf8rY0e_PR4=jS(y{u)L9 zcLDkr6n*4+>Hp&Z{l6+4IbG_1t?Ub(vSVx-OR#uEzN{g{yIPi~NXYyvjKD3XXZWP2o=pj{Sx^ zQtF>pxVjJDRQ%wMmim_zjxSQl|E&1I-7Wc&qL2R(lJkY4x~9~2z^TNHjo;rJ$!`WeMfSmCou{Hp)q0Dag(&@X;c4DlklyeBh0zI^X#xv8XM zjWCU}tyfOSx2&D8G{>HFm^NlP7Sl#@Ii_XPs6aiUb=OwuDjQ8FlXi+MQfbH5=nHl` zCF;>5qCTF=Yng1CGOsg5rtoi1(CuYW;{N|gnB3q<`@al(i9x2te0sI(zdf*Lq0%cA zM0o*=OY*L;#~Ps@`JIU~1NkBSz{PR`ajE$Fm0YABS!H+A8+?9W`v}>>r}y1SFG6Jh z-uJ7dEAh)XdZ}qO`!7ZOyH-s3o3xYVK4IVK)7$F(o#W$Eo1~pA4+(o!2k-lYy`M`v z$tUOq_lJ5W(Dsjj?+?rJ|1RtwY$<6k z_s?p5qpQtgLvI!v1K%R>;kU-jSSK1te(swvUzOcRI;+`NMEobYmz9U#{(rj9 Bi2VQn literal 0 HcmV?d00001 diff --git a/build/debug.o b/build/debug.o new file mode 100644 index 0000000000000000000000000000000000000000..7699e81b2a3f4531f60e845190ec90f3af7656b3 GIT binary patch literal 936 zcmbVK%}N6?5T32|_oO$$%X+ec4ZEdYJV>C_Uc_6$>+UvG(EVXI0ejI`@R54;ary*0 zlT9$qf`<;wOy>LM%g>O{>ElB$2*6qZ_wZL)6kyDQ z77b&i%lKn7V$t~8z*^PEc#6J{K6{!&4`5B$9{PVq$M<3L)9G1=R4rKsz?xMqlN7V8 z+x%izQoKuGi$o^C(xw5Hm3b}-#EMc1hW8jYGRa;|y(|=~>ar5GTy@Ud5x77dz2U&q zbFa3gGj0uCVkFF;6W44v`1&hsIYQr6e}h`uGeUQbn}T@P?D;m|B5Bud-g#JTV06u^R>i(nI`)#ni2I;COdBv{q)Z4h+0!XBi=Rt{%1(~v#0)V LBYHO3CSU&x+nqQQ literal 0 HcmV?d00001 diff --git a/build/execve_interceptor.o b/build/execve_interceptor.o new file mode 100644 index 0000000000000000000000000000000000000000..a96107fbab9c5f87534927e88a89668a40211cd3 GIT binary patch literal 4312 zcmb`JU2GIp6vyxO1F(E-L6l0BPDl|j?X=qhLP6c7v`o#~sPHT#2AcU4?Yl+3a(Lv2VZ%J?GB7?CrSo=1FGm zy}$cE=bo86_ue_!7HuyH1PHePd5{!ZoDx#Cuuu=vYM2DcBJxLY#f=^%dnK|n@Jz85l0)_ON0!?<`ev z<*t^1$SFUxk!0#_v7UT1JEi0xbdD$^UsUx*o{IEEo{p$}Gna!khg`?L3nsOY zg61Q+EwvPl<}(XAa@%SvVSs3`?RrPdYGO9 z_E0>R+(zmc~ z3`iv$k_u#5COYPWu|mmSnj1#KKoyuY*wlFThmUj8>fNiQ>B&>mlOIfFPhCAZUMEeB z9ml@O$*Gr*Ts!vRl_STePLH)nglunZZIRaW^k+;bBZWfpI=Qhvl%dVgfu<(8aot*m zF+P5Jm2lyz*xuPgN(jj#D}@Vfsauf1bB~k2aAlx+!Q6RAVKVA~-_80Ia3XDsDi4>m zE}WwrDSfqUqI`T#*T~$GR0YU8<}+Qf0_U}i{6^=<+h1B_$GDS<=o+3SuV#GJEJ}#P zc-X^TT{($*_Shg{!x}%YVrNz~lWexx`22@km<9eJJX%&)48m5*|>HY}2q-N_}N%q->qpJyP zkfa?umQ0a&CY3N^8bB-Kq%w}`ShQQS2h(a&b7Dh8RZ})R+khGy+5?-m;ec=4Fv+0q z#0a>gA!m2f1P&E&7!W)XTG~;QR@@jcAP>h#>X1`XHR61N-2H>#K1cVszwv+obJw@~ zp5ZtpoNr)`xGyXgxVtW0{Stvc%JjI0-Y)Q7#xV}=sXRWeV>EC4w_HqDCZ2#?|1RU0 zKaRmUt|v5P_>7!?ix3R;xNCC$JwhMxO;tUIV+)KIskdOWiL62*X>rV>$y9EB8z?TbrQiyY#z|RSK zG0sPk;AQxN!Ek<8z{U0R8OLIQ zz?U;g6|4?P#$*tUYLE z4+@14HBg0dDKRXB2)rILBcwVCC!V;JL_- z9Gq($ho48dw$bi|3whyWLQ2S(FfT4~?>Lrdb5Zeu!JzaXncI`-vymmZxlsP-_QK<`9$M>yxawyye{hA_P!9->D3Ma z$9-+qHxBK0n7;&d(Rlux9fAtR^!i_5{t6ee((C^`@M7Oj3O^VyK7ZK6eU1BbUTkdi st7IPvp9kCv78UWwy|vh@+QojHH+f!|r%BK7V*X<+|5qTsXkPz+0We)YCIA2c literal 0 HcmV?d00001 diff --git a/build/init_cleanup.o b/build/init_cleanup.o new file mode 100644 index 0000000000000000000000000000000000000000..7ec000771a39075515103b5c43f06f3a80a34179 GIT binary patch literal 2000 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 E55%mDSO5S3 literal 0 HcmV?d00001 diff --git a/build/logging.o b/build/logging.o new file mode 100644 index 0000000000000000000000000000000000000000..71d4ce6682e3e4b458de4b87c1bc481426d355ad GIT binary patch literal 4736 zcmb`Le{2**6vwAO!SdrOq9Q0=A{bD)c56`}QG2x4Zt<|Dv)s7uz{@^ozk&$XbYde)BV}62|*Z?H7CT#1^tn_U3 zRC%7RIyD~8*RLje55nXpJgK-=zDT^JC-I^@S`|ru~$u~XVmXJ zX1^9c`pu2eQ7ztg8k%v{ZcvSnPQj=n;cCAR+Ri=<@T!-!_`YwU=d<>Qi}|&jycsTy z4?B6%UWO|(f99yf{91!d-6m*`rNPN({^m3P*31F!2A{FS(+AUl<2nQtninhwtUdOT zxIRuU9@xbbi0z)3BzD}{*Mr#$UEbk~@3^vBq0hV>mt7qvp<^wWryrYmTR-lf*nN+m z?!RXF#Hz+6Bbd~cMblZkrvAZmTLZpXbes%PWX!uGFOH6m%IAe%zFgl(B^R{fl+>?v z;_fo7bGemg0m!Id#*<67mSxG)KptR~i=tIZLAa?Y5UN?JEQ)5ZK%};EQB9RKC<@d! z>NScHR>IACNNEh$DnTF&N6p3-CCL3O7>+c^z8;B$Bg|`^%gRd2*m#oXBK3xj*~Sv# z6@XHTX*J$euT^e9<-d`H>69cb@OrF|^~*VAmUi+Yb$Y*gLrI?X3!9#RUZ`mBkgC zV<97^sH!{9owHPp@u9jkH`kq$w?tr=2c8#}2?ySR;>Rl(+}H%N6gbdkTMbKkzKkWc zWG2m64m|3>p9hZX zNkEInpCf2-zb2daH3$Bd12-J_eh2=Z1OLE*A93J44*aA8?|0y59Qc3(A9COfs#I-# zsMcN0+`fVwJgIof#nS_L%EQxgJgMBXf_J%c8FnA!W3GRQ@jB_p$``~+%c_m~CY|~H z!RAPP$O!tY>l#?Fx-lHpSxv0DvA#NB=vWAwV}{=d^FUFdd1+?R`r1&Skwx@C4QtYy z;GZ=GYqqL2B*|qE9A*AuU+F53&tF&G|W94 z4#^`3!BC$Lhva(@g4y+lEX+C9G^zhyaLhA>@JoVYp4$nZB}yvtIfN^O-$A%0IOd;9 z_!^?0OZY~@=Mf$z9Dirz`nw6gi}1sQ&nNs-!Erq|5q^y5vj{&;^cjSoC3-sVd7{VP z8oACZ4*EH`5HQ?Nx(|v2UoAK`)8UZ$YaR3k;R?~WJMcXYd_UoIou3Gf%?y&ihv?~k zCJ3i_&XPR%Cy%_Yb40&@@BzW^1$H;#7l?i#;a5q17va~4o~~1V@YwImH1Q#1=eIfV z4G#GgSOXfmg@liN{5;MRV$9spEloyXGqgs;YU^Y#qBjQIhTdW@cTK| zKc+w$d?m1UQOg&DEU}-`Xa7yd+JN^UUkXIK7hh_yI&^~JJA(6I?Lotug?0}d$ZgXw zza5|$47JqmhXLla%l~V<3bB|o7Y=GN{$&cGFXxwSzF_wFVX+{4yu5xHkKc3H&w+#5 zGh*NH`l!h`*{%nt>{H$ABAznr+qHGT@b`v3`>5M1;uRbalk1nL6*`#H9^WJ4Tcl95 z_V^coqcmUm#~ShfEplJ*`N6s`gL%+S^- literal 0 HcmV?d00001 diff --git a/build/rules.o b/build/rules.o new file mode 100644 index 0000000000000000000000000000000000000000..c011107cf1b71afaecedbde84d9fe94027ba0603 GIT binary patch literal 1544 zcmbtU%}*0i5T7m3u6(tA97r&_CxeM>TEanz(QZ)KVlhT6kSOA|E|5q+vimjx6E&um zq`?AzfmiXmF-|50-Vk=p>Js`OW-hX6L=~=yGx-AW0xZ zf(x+k2^8RMVBd~6%s6yGC+vhz{8(L4!T_aecx@dcsbXEyUwxAG@)vDNn@m<-1eG9w zmP(X=X*VYH$}^=6KreoildJRccJNkiV$ZfP^xZEbd@7C!leQnBu)9ILtljl>#^4i670eW|pQ zV~!Gwse@{?Kjt*t*u#MVH9B~j!;Lb~iYkH!M}^U=DZtOK64ru;Pjp9C0%KjlOY1Fbtz(t8k*C38C@|TM`H7Be_*bjF-g@``1Lyor z(dV|p_g%kui_eW6!o(vkyfF)6G&g*Ef;d&wfs=b_LMjAD=nfn4i#c}bzco?>Y;n7sXEoac7n*Yj=A(v`K@wi3wr}}OY{e>RF zps?L}NBuyb+%d#Lcn-WF^m{m8LE9~2e*#ORL8)H;S6veZ=2ftv2f%ctL~_wI-y^ZxX{+``N5L5I=u<4<$`;$CLc@bZ5H*0r7L literal 0 HcmV?d00001 diff --git a/build/utils.o b/build/utils.o new file mode 100644 index 0000000000000000000000000000000000000000..9da22ca2e1519906f8ba5d14bedd19c6f9e5a61f GIT binary patch literal 2376 zcmbW1O^j1j6vt2J18{)pC@cs=oF+y^BX9a9xN!k(=BsEm#Lxu+QeNM@(uVf+@$PK` zXk;cCO-gLy!nKJDmn0-^)C5u;LS*GucW#U(0|7r)gfO1}yZ3fpURoBM^uBZM@BPoY z_uY?PTP!Y(q*7!oMaO8nXDHFn13o5=UY9#Y2uGX2Ks;Ul$r~9L>-NBsgUjA(U+_{aa zm7ZD0tZ4Pte<<7j)+oQj#0yHU#OaxZzE1wS`L*u<6XkuidDrf3{!%sduwHg=_4u?L z-$>8oc*NCfsWa&>dmFPs*m7rIU72-T%_fC3LHG*7^f7JXA1%+%zmqv!sd)y9i=cQQv=-ZgR$t|fx-rNwLAHtW1@b`!C(hz=@ zIp&$gLb3JNv@PomVYy@#=d*a&c+62%P+{i<;MH&;?HhL4AeFW#I>5-Ivv} zTf0crR^a(m<+p-_3|$d$&uz4XhZ>GA>Sa&3PT-Y=cd709t{06z9X-`~+R5>gEoE3Y z7@w=?Oc{PGqDsGuW5X9UhaTt9aI6mu40~;O0LTVD!OifG0ohOor^4`cKsM-cE)CxR zWCP#B&F}|+Y)PJpsH%@KjGfd07@FB1vc#39bSms+sC>;tq1SLM>0Op&tvJ#lt0Dwh zVGA9|ZHqS%x8Czv;G3N@cM-{xElh5H^iGyW@a$g!E0@j1=13Ed4X!2IH7@{B*hFHIcR{Wb^=(4J<7 zdl^5gsPntd&!7`Cv;GEM;sDZQz5(ZrQ2S(lgZZHSKY+{0X4VCF68GEWoBba+HtWvo r37yp6fxC+{n#@Pd -#include -#include // 添加 errno 相关定义 -#include -#include -#include -#include // 添加 SIGCHLD 相关定义 -#include // 引入 bool 类型 -#include -#include -#include -#include -#include // 添加 select 相关定义 -#include -#include -#include -#include - -#ifdef DEBUG - -// getpid要用到 -#include -#include - -void print_stacktrace() { - void *buffer[100]; - int size = backtrace(buffer, 100); // 注意这里是 void ** 和 int 参数 - backtrace_symbols_fd(buffer, size, STDERR_FILENO); -} - -#define DEBUG_LOG(fmt, ...) \ - fprintf(stderr, "[DEBUG][PID %d] %s:%d:%s(): " fmt "\n", getpid(), \ - __FILE__, __LINE__, __func__, ##__VA_ARGS__) -#else - -#define DEBUG_LOG(fmt, ...) ((void)0) - -#endif - -#define CONFIG_FILE "/tmp/exec_hook/config/execve_rules.json" -#define LOG_FILE "/tmp/exec_hook/logs/execve.log" -#define LOG_OUT_FILE "/tmp/exec_hook/logs/execve_out.log" -#define COMMAND_NOT_FOUND "/usr/lib/command-not-found" - -#define ANSI_COLOR_RED "\033[31m" -#define ANSI_COLOR_YELLOW "\033[33m" -#define ANSI_COLOR_RESET "\033[0m" - -#define SHM_KEY 12345 // 用于标识共享内存的键值,需要确保唯一性 -#define MAX_RULES 100 // 假设最大规则数量 -#define MAX_ARGS 10 // 支持最多 10 个参数 - -typedef struct { - char cmd[256]; - char type[32]; - char msg[1024]; - char args[MAX_ARGS][256]; // 支持最多 MAX_ARGS 个参数 - int arg_count; -} Rule; - -typedef struct { - bool enabled; - Rule rules[MAX_RULES]; - int rule_count; -} ConfigData; - -// 全局变量,指向共享内存中的配置数据 -static ConfigData *shared_config = NULL; -static int shm_id = -1; -static time_t last_modified_time = 0; -// static int is_initialized = 0; - -// 加载配置到共享内存 -int load_config_to_shm() { - DEBUG_LOG("Loading configuration from %s to shared memory", CONFIG_FILE); - json_object *root = json_object_from_file(CONFIG_FILE); - if (!root) { - DEBUG_LOG("Failed to parse config file from %s", CONFIG_FILE); - return -1; - } - - ConfigData temp_config; - temp_config.enabled = false; - temp_config.rule_count = 0; - - json_object *enabled_obj; - if (json_object_object_get_ex(root, "enabled", &enabled_obj)) { - temp_config.enabled = json_object_get_boolean(enabled_obj); - } - - if (!temp_config.enabled) { - json_object_put(root); - return 0; // 功能未启用,不加载规则 - } - - json_object *rules_array_obj; - if (json_object_object_get_ex(root, "rules", &rules_array_obj) && - json_object_get_type(rules_array_obj) == json_type_array) { - int rules_len = json_object_array_length(rules_array_obj); - temp_config.rule_count = rules_len < MAX_RULES ? rules_len : MAX_RULES; - - for (int i = 0; i < temp_config.rule_count; i++) { - json_object *rule_obj = - json_object_array_get_idx(rules_array_obj, i); - json_object *cmd, *type, *msg, *args; - - json_object_object_get_ex(rule_obj, "cmd", &cmd); - json_object_object_get_ex(rule_obj, "type", &type); - json_object_object_get_ex(rule_obj, "msg", &msg); - - if (cmd) - strncpy(temp_config.rules[i].cmd, json_object_get_string(cmd), - sizeof(temp_config.rules[i].cmd) - 1); - if (type) - strncpy(temp_config.rules[i].type, json_object_get_string(type), - sizeof(temp_config.rules[i].type) - 1); - if (msg) - strncpy(temp_config.rules[i].msg, json_object_get_string(msg), - sizeof(temp_config.rules[i].msg) - 1); - - // 解析 args 参数 - temp_config.rules[i].arg_count = 0; - if (json_object_object_get_ex(rule_obj, "args", &args) && - json_object_get_type(args) == json_type_array) { - int args_len = json_object_array_length(args); - temp_config.rules[i].arg_count = - args_len < MAX_ARGS ? args_len - : MAX_ARGS; // 限制最多 MAX_ARGS 个参数 - - for (int j = 0; j < temp_config.rules[i].arg_count; j++) { - json_object *arg_item = json_object_array_get_idx(args, j); - if (arg_item) { - strncpy(temp_config.rules[i].args[j], - json_object_get_string(arg_item), - sizeof(temp_config.rules[i].args[j]) - 1); - } - } - } - } - } - - json_object_put(root); - - // 将临时配置复制到共享内存 - memcpy(shared_config, &temp_config, sizeof(ConfigData)); - - DEBUG_LOG("Loaded %d rules to shared memory", shared_config->rule_count); - return 0; -} - -// 检查 args 是否匹配 -int args_match(char *const argv[], Rule *rule) { - DEBUG_LOG("Matching args for rule with cmd: %s", rule->cmd); - if (rule->arg_count == 0) { - return 1; // 没有 args 约束,则直接匹配 - } - - for (int i = 0; i < rule->arg_count; i++) { - int found = 0; - for (int j = 1; argv[j] != NULL; j++) { // 跳过 argv[0] (命令本身) - if (strcmp(argv[j], rule->args[i]) == 0) { - found = 1; - break; - } - } - if (!found) return 0; // 只要有一个参数没有匹配,则不符合规则 - } - return 1; -} - -// 写入日志 -void write_log(const char *filename, char *const argv[]) { - DEBUG_LOG("Writing exec log for command: %s", filename); - time_t now; - time(&now); - - FILE *log = fopen(LOG_FILE, "a"); - if (!log) return; - - fprintf(log, "[%s] Command: %s\n", ctime(&now), filename); - - for (int i = 0; argv[i]; i++) { - fprintf(log, "arg[%d]: %s\n", i, argv[i]); - } - - fclose(log); -} - -// 判断字符是否为 ANSI 转义序列 -int is_ansi_escape_sequence(const char *str) { - // ANSI 转义序列的常见格式是以 ESC 开头,后跟 '[', 'm' 等 - return str[0] == '\033' && str[1] == '['; -} - -// // 保存原始的 write 函数指针 -// static ssize_t (*original_write)(int fd, const void *buf, size_t count) = -// NULL; - -// // 保存日志文件描述符 -// static int log_fd = -1; - -// ssize_t write(int fd, const void *buf, size_t count) { -// ssize_t result = -1; - -// result = original_write(fd, buf, count); -// // 如果原始 write 成功,则将相同的内容写入日志文件 -// if (result > 0 && log_fd != -1) { -// ssize_t log_result = original_write(log_fd, buf, count); -// if (log_result == -1) { -// fprintf(stderr, "Error writing to log file: %s\n", -// strerror(errno)); -// // 注意:这里不应该影响原始 write 的返回值 -// } -// } -// return result; -// } - -typedef int (*orig_execve_type)(const char *filename, char *const argv[], - char *const envp[]); - -// 原始指针 -static orig_execve_type orig_execve = NULL; - -// 判断父进程是否为终端 shell (bash, zsh, fish 等) -int is_terminal_shell() { - pid_t ppid = getppid(); - char path[64], proc_name[256]; - FILE *file; - - snprintf(path, sizeof(path), "/proc/%d/comm", ppid); - file = fopen(path, "r"); - if (!file) return 0; - - if (fgets(proc_name, sizeof(proc_name), file)) { - proc_name[strcspn(proc_name, "\n")] = 0; // 去除换行符 - if (strcmp(proc_name, "bash") == 0 || strcmp(proc_name, "zsh") == 0 || - strcmp(proc_name, "fish") == 0 || strcmp(proc_name, "sh") == 0) { - fclose(file); - return 1; - } - } - fclose(file); - return 0; -} - -// 检查配置文件是否已修改 -int config_file_modified() { - struct stat file_stat; - DEBUG_LOG("Checking if config file has been modified: %s", CONFIG_FILE); - if (stat(CONFIG_FILE, &file_stat) != 0) { - DEBUG_LOG("Cannot get stat for FILE: %s", CONFIG_FILE); - return 0; - } - int isChanged = file_stat.st_mtime != last_modified_time; - if (isChanged != 0) { - DEBUG_LOG("Updating last_modified_time to: %ld", file_stat.st_mtime); - last_modified_time = file_stat.st_mtime; - return 1; - } - return 0; -} - -// 加载或重新加载配置到共享内存 -void load_config_if_needed() { - if (shared_config == NULL) { - // 首次加载,创建共享内存 - DEBUG_LOG("Creating shared memory for config data"); - shm_id = shmget(SHM_KEY, sizeof(ConfigData), IPC_CREAT | 0644); - if (shm_id == -1) { - perror("shmget failed"); - return; - } - shared_config = (ConfigData *)shmat(shm_id, NULL, 0); - if (shared_config == (void *)-1) { - perror("shmat failed"); - shared_config = NULL; - return; - } - // 首次加载时读取配置文件 - DEBUG_LOG("Loading config file for the first time"); - struct stat file_stat; - if (stat(CONFIG_FILE, &file_stat) == 0) { - last_modified_time = file_stat.st_mtime; - load_config_to_shm(); - } else { - DEBUG_LOG("Cannot get stat for FILE: %s", CONFIG_FILE); - // 初始化一个空的配置 - shared_config->enabled = false; - shared_config->rule_count = 0; - } - } else if (config_file_modified()) { - DEBUG_LOG("Config file has been modified."); - load_config_to_shm(); - } else { - DEBUG_LOG("Config file has not been modified, skipping reload."); - } -} - -// 复制 stdout/stderr 到日志文件,同时保留终端颜色 -void duplicate_output_to_log() { - DEBUG_LOG("Duplicating stdout/stderr to log file: %s", LOG_OUT_FILE); - - int log_fd = open(LOG_OUT_FILE, O_WRONLY | O_CREAT | O_APPEND, 0644); - if (log_fd == -1) { - perror("Failed to open log file"); - return; - } - - int master_fd, slave_fd; - if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) == -1) { - perror("openpty failed"); - close(log_fd); - return; - } - - pid_t pid = fork(); - if (pid == -1) { - perror("fork failed"); - close(log_fd); - close(master_fd); - close(slave_fd); - return; - } - - if (pid == 0) { // 子进程 - close(master_fd); - - // 连接 slave_fd 到标准输入输出错误 - dup2(slave_fd, STDIN_FILENO); - dup2(slave_fd, STDOUT_FILENO); - dup2(slave_fd, STDERR_FILENO); - close(slave_fd); - - // 子进程不做输出,只保留环境等待 execve - return; // 留给你调用 execve - } - - // 父进程(主控):读取 master_fd 并写入 stdout + 日志 - close(slave_fd); - - // 忽略子进程退出信号 - signal(SIGCHLD, SIG_IGN); - - char buffer[1024]; - ssize_t n; - int has_error = 0; - - while ((n = read(master_fd, buffer, sizeof(buffer))) > 0) { - // 检查错误 - if (memmem(buffer, n, "error", 5) || memmem(buffer, n, "Error", 5) || - memmem(buffer, n, "ERROR", 5)) { - has_error = 1; - } - - // // 输出到终端 - // if (write(STDOUT_FILENO, buffer, n) == -1) { - // perror("Failed to write to stdout"); - // } - - // 写入日志 - if (write(log_fd, buffer, n) == -1) { - perror("Failed to write to log file"); - } - } - - if (has_error) { - printf("\n检测到命令执行出错,已经上报北冥论坛~ \n"); - fflush(stdout); - } - - close(master_fd); - close(log_fd); -} - -int execve(const char *filename, char *const argv[], char *const envp[]) { - // if (!is_initialized) { - // initialize(); - // } - DEBUG_LOG("Intercepted execve for: %s", filename); - DEBUG_LOG("argv[0] = %s", argv[0]); - - orig_execve = (orig_execve_type)dlsym(RTLD_NEXT, "execve"); - if (orig_execve == NULL) { - fprintf(stderr, "Error in dlsym(\"execve\"): %s\n", dlerror()); - exit(EXIT_FAILURE); - } - - // 加载配置(仅在需要时) - load_config_if_needed(); - - // 仅在 shell 终端调用 execve 时拦截 - if (!is_terminal_shell()) { - DEBUG_LOG("Not a terminal shell, bypassing interception."); - return orig_execve(filename, argv, envp); - } - - // 当前配置信息 - DEBUG_LOG("Current Config rule count : %d", shared_config->rule_count); - - // 如果共享内存未成功加载,则直接执行 - if (shared_config == NULL) { - DEBUG_LOG("Shared memory not initialized, bypassing interception."); - return orig_execve(filename, argv, envp); - } - - // 如果功能被禁用,则直接执行 - if (!shared_config->enabled) { - DEBUG_LOG("Not enabled."); - return orig_execve(filename, argv, envp); - } - - write_log(filename, argv); - - const char *basename = argv[0]; - if (strcmp(filename, COMMAND_NOT_FOUND) == 0 && argv[2]) { - basename = argv[2]; - } - - // 特殊处理以 shell.posix - // 方式执行的命令,直接执行,不进行规则匹配和输出重定向 - if (argv[1] != NULL && strcmp(argv[1], "shell.posix") == 0) { - return orig_execve(filename, argv, envp); - } - - for (int i = 0; i < shared_config->rule_count; i++) { - if (strcmp(basename, shared_config->rules[i].cmd) == 0 && - args_match(argv, &shared_config->rules[i])) { - DEBUG_LOG("Rule matched: %s (type: %s)", - shared_config->rules[i].cmd, - shared_config->rules[i].type); - if (strcmp(shared_config->rules[i].type, "warn") == 0) { - printf(ANSI_COLOR_YELLOW "[Warning] %s\n" ANSI_COLOR_RESET, - shared_config->rules[i].msg); - printf("按下 'Y' 继续执行, 或按任意键取消: "); - char input = getchar(); - if (input != 'Y' && input != 'y') { - printf("\nExecution cancelled.\n"); - exit(EXIT_FAILURE); - // return -1; - } - printf("\nContinuing execution...\n"); - } else if (strcmp(shared_config->rules[i].type, "error") == 0) { - printf(ANSI_COLOR_RED "[Error] %s" ANSI_COLOR_RESET "\n", - shared_config->rules[i].msg); - exit(EXIT_FAILURE); - // return -1; - } - break; - } - } - - // 复制 stdout 和 stderr 到日志文件 - duplicate_output_to_log(); - - return orig_execve(filename, argv, envp); -} - -// // 构造函数,在库被加载时执行 -// __attribute__((constructor)) static void initialize() { -// if (is_initialized) return; -// is_initialized = 1; -// DEBUG_LOG("Initializing execve_intercept library."); -// // // 获取原始的 write 函数 -// // original_write = dlsym(RTLD_NEXT, "write"); -// // if (original_write == NULL) { -// // fprintf(stderr, "Error in dlsym(\"write\"): %s\n", dlerror()); -// // exit(EXIT_FAILURE); -// // } - -// // // 打开日志文件,以追加模式打开,如果不存在则创建 -// // log_fd = open(LOG_OUT_FILE, O_WRONLY | O_CREAT | O_APPEND, 0644); -// // if (log_fd == -1) { -// // fprintf(stderr, "Error opening log file \"%s\": %s\n", -// LOG_OUT_FILE, -// // strerror(errno)); -// // exit(EXIT_FAILURE); -// // } - -// load_config_if_needed(); -// orig_execve = (orig_execve_type)dlsym(RTLD_NEXT, "execve"); -// if (orig_execve == NULL) { -// fprintf(stderr, "Error in dlsym(\"execve\"): %s\n", dlerror()); -// exit(EXIT_FAILURE); -// } -// } - -// 在库卸载时分离和删除共享内存 -__attribute__((destructor)) static void cleanup_shared_memory() { - DEBUG_LOG("execve_intercept library unloaded."); - // log输出路径 - DEBUG_LOG("Log file: %s", LOG_FILE); - DEBUG_LOG("Log out file: %s", LOG_OUT_FILE); - DEBUG_LOG("Config file: %s", CONFIG_FILE); - DEBUG_LOG("Shared memory ID: %d", shm_id); - if (shared_config != NULL) { - DEBUG_LOG("Cleaning up shared memory."); - // 解除共享内存映射 - if (shmdt(shared_config) == -1) { - perror("shmdt failed"); - } - shared_config = NULL; - } -#ifdef DEBUG - print_stacktrace(); -#endif - - // if (log_fd != -1) { - // DEBUG_LOG("Closing log file descriptor."); - // close(log_fd); - // } - // 注意:这里不删除共享内存段,因为可能被其他进程使用。 - // 如果需要删除,需要一个明确的机制来判断是否是最后一个使用者。 - // 例如,可以创建一个单独的工具来管理共享内存的生命周期。 -} diff --git a/intercept.so b/intercept.so deleted file mode 100755 index f9bebb3246fd953b2a671d355c2fde3a591d4b13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30672 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 +#include +#include +#include +#include +#include + +// Global variables (defined in execve_interceptor.c) +extern ConfigData *shared_config; +extern int shm_id; +extern time_t last_modified_time; + +// Load configuration to shared memory +int load_config_to_shm() { + DEBUG_LOG("Loading configuration from %s to shared memory", CONFIG_FILE); + json_object *root = json_object_from_file(CONFIG_FILE); + if (!root) { + DEBUG_LOG("Failed to parse config file from %s", CONFIG_FILE); + return -1; + } + + ConfigData temp_config; + temp_config.enabled = false; + temp_config.rule_count = 0; + + json_object *enabled_obj; + if (json_object_object_get_ex(root, "enabled", &enabled_obj)) { + temp_config.enabled = json_object_get_boolean(enabled_obj); + } + + if (!temp_config.enabled) { + json_object_put(root); + return 0; // Feature not enabled, don't load rules + } + + json_object *rules_array_obj; + if (json_object_object_get_ex(root, "rules", &rules_array_obj) && + json_object_get_type(rules_array_obj) == json_type_array) { + int rules_len = json_object_array_length(rules_array_obj); + temp_config.rule_count = rules_len < MAX_RULES ? rules_len : MAX_RULES; + + for (int i = 0; i < temp_config.rule_count; i++) { + json_object *rule_obj = + json_object_array_get_idx(rules_array_obj, i); + json_object *cmd, *type, *msg, *args; + + json_object_object_get_ex(rule_obj, "cmd", &cmd); + json_object_object_get_ex(rule_obj, "type", &type); + json_object_object_get_ex(rule_obj, "msg", &msg); + + if (cmd) + strncpy(temp_config.rules[i].cmd, json_object_get_string(cmd), + sizeof(temp_config.rules[i].cmd) - 1); + if (type) + strncpy(temp_config.rules[i].type, json_object_get_string(type), + sizeof(temp_config.rules[i].type) - 1); + if (msg) + strncpy(temp_config.rules[i].msg, json_object_get_string(msg), + sizeof(temp_config.rules[i].msg) - 1); + + // Parse args parameter + temp_config.rules[i].arg_count = 0; + if (json_object_object_get_ex(rule_obj, "args", &args) && + json_object_get_type(args) == json_type_array) { + int args_len = json_object_array_length(args); + temp_config.rules[i].arg_count = + args_len < MAX_ARGS ? args_len + : MAX_ARGS; // Limit to MAX_ARGS parameters + + for (int j = 0; j < temp_config.rules[i].arg_count; j++) { + json_object *arg_item = json_object_array_get_idx(args, j); + if (arg_item) { + strncpy(temp_config.rules[i].args[j], + json_object_get_string(arg_item), + sizeof(temp_config.rules[i].args[j]) - 1); + } + } + } + } + } + + json_object_put(root); + + // Copy the temporary configuration to shared memory + memcpy(shared_config, &temp_config, sizeof(ConfigData)); + + DEBUG_LOG("Loaded %d rules to shared memory", shared_config->rule_count); + return 0; +} + +// Check if the configuration file has been modified +int config_file_modified() { + struct stat file_stat; + DEBUG_LOG("Checking if config file has been modified: %s", CONFIG_FILE); + if (stat(CONFIG_FILE, &file_stat) != 0) { + DEBUG_LOG("Cannot get stat for FILE: %s", CONFIG_FILE); + return 0; + } + int isChanged = file_stat.st_mtime != last_modified_time; + if (isChanged != 0) { + DEBUG_LOG("Updating last_modified_time to: %ld", file_stat.st_mtime); + last_modified_time = file_stat.st_mtime; + return 1; + } + return 0; +} + +// Load or reload configuration to shared memory if needed +void load_config_if_needed() { + if (shared_config == NULL) { + // First load, create shared memory + DEBUG_LOG("Creating shared memory for config data"); + shm_id = shmget(SHM_KEY, sizeof(ConfigData), IPC_CREAT | 0644); + if (shm_id == -1) { + perror("shmget failed"); + return; + } + shared_config = (ConfigData *)shmat(shm_id, NULL, 0); + if (shared_config == (void *)-1) { + perror("shmat failed"); + shared_config = NULL; + return; + } + // Read config file on first load + DEBUG_LOG("Loading config file for the first time"); + struct stat file_stat; + if (stat(CONFIG_FILE, &file_stat) == 0) { + last_modified_time = file_stat.st_mtime; + load_config_to_shm(); + } else { + DEBUG_LOG("Cannot get stat for FILE: %s", CONFIG_FILE); + // Initialize an empty configuration + shared_config->enabled = false; + shared_config->rule_count = 0; + } + } else if (config_file_modified()) { + DEBUG_LOG("Config file has been modified."); + load_config_to_shm(); + } else { + DEBUG_LOG("Config file has not been modified, skipping reload."); + } +} \ No newline at end of file diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..73cbd3a --- /dev/null +++ b/src/config.h @@ -0,0 +1,10 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include "exec_hook.h" + +int load_config_to_shm(); +int config_file_modified(); +void load_config_if_needed(); + +#endif // CONFIG_H \ No newline at end of file diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..cc73b52 --- /dev/null +++ b/src/debug.c @@ -0,0 +1,11 @@ +#ifdef DEBUG +#include +#include +#include + +void print_stacktrace() { + void *buffer[100]; + int size = backtrace(buffer, 100); + backtrace_symbols_fd(buffer, size, STDERR_FILENO); +} +#endif \ No newline at end of file diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..90c88eb --- /dev/null +++ b/src/debug.h @@ -0,0 +1,15 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#ifdef DEBUG +#include + +void print_stacktrace(); +#define DEBUG_LOG(fmt, ...) \ + fprintf(stderr, "[DEBUG][PID %d] %s:%d:%s(): " fmt "\n", getpid(), \ + __FILE__, __LINE__, __func__, ##__VA_ARGS__) +#else +#define DEBUG_LOG(fmt, ...) ((void)0) +#endif + +#endif // DEBUG_H \ No newline at end of file diff --git a/src/exec_hook.h b/src/exec_hook.h new file mode 100644 index 0000000..1fd00d5 --- /dev/null +++ b/src/exec_hook.h @@ -0,0 +1,40 @@ +#ifndef EXEC_HOOK_H +#define EXEC_HOOK_H + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "struct.h" + +#define CONFIG_FILE "/tmp/exec_hook/config/execve_rules.json" +#define LOG_FILE "/tmp/exec_hook/logs/execve.log" +#define LOG_OUT_FILE "/tmp/exec_hook/logs/execve_out.log" +#define COMMAND_NOT_FOUND "/usr/lib/command-not-found" + +#define ANSI_COLOR_RED "\033[31m" +#define ANSI_COLOR_YELLOW "\033[33m" +#define ANSI_COLOR_RESET "\033[0m" + +#define SHM_KEY 12345 + +// Global variable, pointing to the configuration data in shared memory +extern ConfigData *shared_config; +extern int shm_id; +extern time_t last_modified_time; +// extern int is_initialized; + +#endif // EXEC_HOOK_H \ No newline at end of file diff --git a/src/execve_interceptor.c b/src/execve_interceptor.c new file mode 100644 index 0000000..325176a --- /dev/null +++ b/src/execve_interceptor.c @@ -0,0 +1,106 @@ +#include "execve_interceptor.h" + +#include +#include +#include +#include +#include + +#include "config.h" +#include "debug.h" +#include "init_cleanup.h" +#include "logging.h" +#include "rules.h" +#include "utils.h" + +// Global variables (declared in exec_hook.h and defined here) +ConfigData *shared_config = NULL; +int shm_id = -1; +time_t last_modified_time = 0; +// int is_initialized = 0; + +// Original pointer +orig_execve_type orig_execve = NULL; + +int execve(const char *filename, char *const argv[], char *const envp[]) { + // if (!is_initialized) { + // initialize(); + // } + DEBUG_LOG("Intercepted execve for: %s", filename); + DEBUG_LOG("argv[0] = %s", argv[0]); + + orig_execve = (orig_execve_type)dlsym(RTLD_NEXT, "execve"); + if (orig_execve == NULL) { + fprintf(stderr, "Error in dlsym(\"execve\"): %s\n", dlerror()); + exit(EXIT_FAILURE); + } + + // Load configuration (only if needed) + load_config_if_needed(); + + // Intercept only when execve is called from a shell terminal + if (!is_terminal_shell()) { + DEBUG_LOG("Not a terminal shell, bypassing interception."); + return orig_execve(filename, argv, envp); + } + + // Current configuration information + DEBUG_LOG("Current Config rule count : %d", shared_config->rule_count); + + // If shared memory was not successfully loaded, execute directly + if (shared_config == NULL) { + DEBUG_LOG("Shared memory not initialized, bypassing interception."); + return orig_execve(filename, argv, envp); + } + + // If the feature is disabled, execute directly + if (!shared_config->enabled) { + DEBUG_LOG("Not enabled."); + return orig_execve(filename, argv, envp); + } + + write_log(filename, argv); + + const char *basename = argv[0]; + if (strcmp(filename, COMMAND_NOT_FOUND) == 0 && argv[2]) { + basename = argv[2]; + } + + // Special handling for commands executed via shell.posix + // Execute directly, without rule matching and output redirection + if (argv[1] != NULL && strcmp(argv[1], "shell.posix") == 0) { + return orig_execve(filename, argv, envp); + } + + for (int i = 0; i < shared_config->rule_count; i++) { + if (strcmp(basename, shared_config->rules[i].cmd) == 0 && + args_match(argv, &shared_config->rules[i])) { + DEBUG_LOG("Rule matched: %s (type: %s)", + shared_config->rules[i].cmd, + shared_config->rules[i].type); + if (strcmp(shared_config->rules[i].type, "warn") == 0) { + printf(ANSI_COLOR_YELLOW "[Warning] %s\n" ANSI_COLOR_RESET, + shared_config->rules[i].msg); + printf("按下 'Y' 继续执行, 或按任意键取消: "); + char input = getchar(); + if (input != 'Y' && input != 'y') { + printf("\nExecution cancelled.\n"); + exit(EXIT_FAILURE); + // return -1; + } + printf("\nContinuing execution...\n"); + } else if (strcmp(shared_config->rules[i].type, "error") == 0) { + printf(ANSI_COLOR_RED "[Error] %s" ANSI_COLOR_RESET "\n", + shared_config->rules[i].msg); + exit(EXIT_FAILURE); + // return -1; + } + break; + } + } + + // Duplicate stdout and stderr to the log file + duplicate_output_to_log(); + + return orig_execve(filename, argv, envp); +} \ No newline at end of file diff --git a/src/execve_interceptor.h b/src/execve_interceptor.h new file mode 100644 index 0000000..5225ee1 --- /dev/null +++ b/src/execve_interceptor.h @@ -0,0 +1,14 @@ +#ifndef EXECVE_INTERCEPTOR_H +#define EXECVE_INTERCEPTOR_H + +#include "exec_hook.h" + +// Original execve type +typedef int (*orig_execve_type)(const char *filename, char *const argv[], + char *const envp[]); + +extern orig_execve_type orig_execve; + +int execve(const char *filename, char *const argv[], char *const envp[]); + +#endif // EXECVE_INTERCEPTOR_H \ No newline at end of file diff --git a/src/init_cleanup.c b/src/init_cleanup.c new file mode 100644 index 0000000..5958a7b --- /dev/null +++ b/src/init_cleanup.c @@ -0,0 +1,43 @@ +#include "init_cleanup.h" +#include "exec_hook.h" +#include "debug.h" +#include +#include +#include + +// Global variables (defined in execve_interceptor.c) +extern ConfigData *shared_config; +extern int shm_id; + +// // Constructor, executed when the library is loaded +// __attribute__((constructor)) static void initialize() { +// if (is_initialized) return; +// is_initialized = 1; +// DEBUG_LOG("Initializing execve_intercept library."); +// load_config_if_needed(); +// // orig_execve is initialized in the execve function itself +// } + +// Destructor, executed when the library is unloaded +__attribute__((destructor)) static void cleanup_shared_memory() { + DEBUG_LOG("execve_intercept library unloaded."); + // Log output paths + DEBUG_LOG("Log file: %s", LOG_FILE); + DEBUG_LOG("Log out file: %s", LOG_OUT_FILE); + DEBUG_LOG("Config file: %s", CONFIG_FILE); + DEBUG_LOG("Shared memory ID: %d", shm_id); + if (shared_config != NULL) { + DEBUG_LOG("Cleaning up shared memory."); + // Detach shared memory segment + if (shmdt(shared_config) == -1) { + perror("shmdt failed"); + } + shared_config = NULL; + } +#ifdef DEBUG + print_stacktrace(); +#endif + // Note: We don't delete the shared memory segment here, as it might be + // used by other processes. A separate mechanism would be needed to manage + // the lifecycle of the shared memory if deletion is required. +} \ No newline at end of file diff --git a/src/init_cleanup.h b/src/init_cleanup.h new file mode 100644 index 0000000..aa07e6a --- /dev/null +++ b/src/init_cleanup.h @@ -0,0 +1,7 @@ +#ifndef INIT_CLEANUP_H +#define INIT_CLEANUP_H + +// void initialize(); +__attribute__((destructor)) static void cleanup_shared_memory(); + +#endif // INIT_CLEANUP_H \ No newline at end of file diff --git a/src/logging.c b/src/logging.c new file mode 100644 index 0000000..2a3e764 --- /dev/null +++ b/src/logging.c @@ -0,0 +1,100 @@ +#include "logging.h" +#include "exec_hook.h" +#include "debug.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// Write log +void write_log(const char *filename, char *const argv[]) { + DEBUG_LOG("Writing exec log for command: %s", filename); + time_t now; + time(&now); + + FILE *log = fopen(LOG_FILE, "a"); + if (!log) return; + + fprintf(log, "[%s] Command: %s\n", ctime(&now), filename); + + for (int i = 0; argv[i]; i++) { + fprintf(log, "arg[%d]: %s\n", i, argv[i]); + } + + fclose(log); +} + +// Duplicate stdout/stderr to log file, while preserving terminal colors +void duplicate_output_to_log() { + DEBUG_LOG("Duplicating stdout/stderr to log file: %s", LOG_OUT_FILE); + + int log_fd = open(LOG_OUT_FILE, O_WRONLY | O_CREAT | O_APPEND, 0644); + if (log_fd == -1) { + perror("Failed to open log file"); + return; + } + + int master_fd, slave_fd; + if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) == -1) { + perror("openpty failed"); + close(log_fd); + return; + } + + pid_t pid = fork(); + if (pid == -1) { + perror("fork failed"); + close(log_fd); + close(master_fd); + close(slave_fd); + return; + } + + if (pid == 0) { // Child process + close(master_fd); + + // Connect slave_fd to standard input/output/error + dup2(slave_fd, STDIN_FILENO); + dup2(slave_fd, STDOUT_FILENO); + dup2(slave_fd, STDERR_FILENO); + close(slave_fd); + + // Child process does not output, only keeps the environment for execve + return; // Will be replaced by the original execve call + } + + // Parent process (controller): read from master_fd and write to stdout + log + close(slave_fd); + + // Ignore child process exit signal + signal(SIGCHLD, SIG_IGN); + + char buffer[1024]; + ssize_t n; + int has_error = 0; + + while ((n = read(master_fd, buffer, sizeof(buffer))) > 0) { + // Check for errors + if (memmem(buffer, n, "error", 5) || memmem(buffer, n, "Error", 5) || + memmem(buffer, n, "ERROR", 5)) { + has_error = 1; + } + + // Write to log + if (write(log_fd, buffer, n) == -1) { + perror("Failed to write to log file"); + } + } + + if (has_error) { + printf("\n检测到命令执行出错,已经上报北冥论坛~ \n"); + fflush(stdout); + } + + close(master_fd); + close(log_fd); +} \ No newline at end of file diff --git a/src/logging.h b/src/logging.h new file mode 100644 index 0000000..7daf1b0 --- /dev/null +++ b/src/logging.h @@ -0,0 +1,7 @@ +#ifndef LOGGING_H +#define LOGGING_H + +void write_log(const char *filename, char *const argv[]); +void duplicate_output_to_log(); + +#endif // LOGGING_H \ No newline at end of file diff --git a/src/rules.c b/src/rules.c new file mode 100644 index 0000000..a7ae738 --- /dev/null +++ b/src/rules.c @@ -0,0 +1,23 @@ +#include "rules.h" +#include "debug.h" +#include + +// Check if args match +int args_match(char *const argv[], Rule *rule) { + DEBUG_LOG("Matching args for rule with cmd: %s", rule->cmd); + if (rule->arg_count == 0) { + return 1; // No args constraint, so it matches + } + + for (int i = 0; i < rule->arg_count; i++) { + int found = 0; + for (int j = 1; argv[j] != NULL; j++) { // Skip argv[0] (command itself) + if (strcmp(argv[j], rule->args[i]) == 0) { + found = 1; + break; + } + } + if (!found) return 0; // If any argument doesn't match, the rule doesn't apply + } + return 1; +} \ No newline at end of file diff --git a/src/rules.h b/src/rules.h new file mode 100644 index 0000000..72d42d2 --- /dev/null +++ b/src/rules.h @@ -0,0 +1,8 @@ +#ifndef RULES_H +#define RULES_H + +#include "exec_hook.h" + +int args_match(char *const argv[], Rule *rule); + +#endif // RULES_H \ No newline at end of file diff --git a/src/struct.h b/src/struct.h new file mode 100644 index 0000000..cf33a9e --- /dev/null +++ b/src/struct.h @@ -0,0 +1,22 @@ +#ifndef STRUCT_H +#define STRUCT_H + +#define _GNU_SOURCE +#define MAX_RULES 100 +#define MAX_ARGS 10 + +typedef struct { + char cmd[256]; + char type[32]; + char msg[1024]; + char args[MAX_ARGS][256]; + int arg_count; +} Rule; + +typedef struct { + bool enabled; + Rule rules[MAX_RULES]; + int rule_count; +} ConfigData; + +#endif // STRUCT_H \ No newline at end of file diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..371d150 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,34 @@ +#include "utils.h" +#include "debug.h" +#include +#include +#include +#include + +// Determine if the parent process is a terminal shell (bash, zsh, fish, etc.) +int is_terminal_shell() { + pid_t ppid = getppid(); + char path[64], proc_name[256]; + FILE *file; + + snprintf(path, sizeof(path), "/proc/%d/comm", ppid); + file = fopen(path, "r"); + if (!file) return 0; + + if (fgets(proc_name, sizeof(proc_name), file)) { + proc_name[strcspn(proc_name, "\n")] = 0; // Remove newline + if (strcmp(proc_name, "bash") == 0 || strcmp(proc_name, "zsh") == 0 || + strcmp(proc_name, "fish") == 0 || strcmp(proc_name, "sh") == 0) { + fclose(file); + return 1; + } + } + fclose(file); + return 0; +} + +// Check if a string is an ANSI escape sequence +int is_ansi_escape_sequence(const char *str) { + // Common format for ANSI escape sequences is ESC followed by '[' + return str[0] == '\033' && str[1] == '['; +} \ No newline at end of file diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..718b690 --- /dev/null +++ b/src/utils.h @@ -0,0 +1,7 @@ +#ifndef UTILS_H +#define UTILS_H + +int is_terminal_shell(); +int is_ansi_escape_sequence(const char *str); + +#endif // UTILS_H \ No newline at end of file diff --git a/test_bash.sh b/test_bash.sh index 0ab6f05..eeff015 100755 --- a/test_bash.sh +++ b/test_bash.sh @@ -35,5 +35,5 @@ echo -e "${CYAN}=============================================${RESET}" HOOK_EXEC_PATH=/tmp/exec_hook/intercept.so rm -rf $HOOK_EXEC_PATH -cp ./intercept.so $HOOK_EXEC_PATH +cp ./build/intercept.so $HOOK_EXEC_PATH LD_PRELOAD=$HOOK_EXEC_PATH bash