主頁 > 軟體工程 > 討論一個注入hook完成后的清理問題,技術討論。。。

討論一個注入hook完成后的清理問題,技術討論。。。

2020-09-25 03:47:43 軟體工程

問題描述:

采用全域鉤子的方式將dll注入了目標行程,并成功hook了目標行程里的函式Fun。使其呼叫時會先進入我的函式Fun_My。這些都沒有問題。但是在我要卸載鉤子的時候,如果剛好代碼執行在我的函式Fun_My的代碼里。就會崩潰。因為我已經卸載了dll,也就是dll已經不在目標行程里了。這時候Fun_My也是無效的內容了,并不是以前的正確的代碼段。所以目標行程就崩潰了。

這種情況下,在我的dll執行detach即將卸載的時候,如何確保代碼并不在Fun_My里面執行呢。

當然我肯定是提前執行了對函式的unhook的,只是最后的一次hook到的函式,可能還在Fun_My里面執行,還沒有執行完回傳。這就出了問題。

大家有遇到過么,或是思考過這個問題,有啥好的處理方法啊,關于技術的意見建議討論都歡迎。感謝。 

uj5u.com熱心網友回復:

參考WinAPIOverride32源代碼?

uj5u.com熱心網友回復:

參考 1 樓 zhao4zhong1 的回復:
參考WinAPIOverride32源代碼?


多謝回復,我研究研究去

uj5u.com熱心網友回復:

一搬都是陣列越界,或指標指向了非法地址造成的。

uj5u.com熱心網友回復:

看下HOOK代碼,跳轉指令是怎么樣的?處理呼叫原函式?

uj5u.com熱心網友回復:

感謝樓上2位回復,不過你們貌似沒看明白問題,還是感謝。

uj5u.com熱心網友回復:

不好處理,即使不涉及hook,僅僅是LoadLibrary,呼叫,FreeLibrary,也存在這種問題。
我做過的所有此類專案,都是注入DLL后直到程式結束也不卸載DLL了,如果要關閉監視,直接令Hook函式呼叫原始函式而不做另外的處理。

uj5u.com熱心網友回復:

參考 6 樓 CharlesSimonyi 的回復:
不好處理,即使不涉及hook,僅僅是LoadLibrary,呼叫,FreeLibrary,也存在這種問題。
我做過的所有此類專案,都是注入DLL后直到程式結束也不卸載DLL了,如果要關閉監視,直接令Hook函式呼叫原始函式而不做另外的處理。


多謝回答,我除錯過幾個專案,確實如你所說,注入dll后,一直存在不會卸載。這確實是個方式。
但同時我也除錯到其他幾個類似軟體,卸載了的。且不會出問題,當然我不100%保證一定沒問題,最少我花 了些時間測驗的,一次都沒出個問題。
目前我正在進一步除錯,大概有個思路了,測驗過繼續和大家討論。

uj5u.com熱心網友回復:

誠如樓上所言,我也認為這是一個普遍問題,只要做這類軟體,一定會面臨這個問題。
我也做了幾個了,一直沒有尋找到一個理想的解決辦法,所以提出來和大家討論討論。
目前有想到個方式,理論上可以優雅的解決這個問題,正在測驗

uj5u.com熱心網友回復:

我 記得 程式 FreeLibrary 后,系統 并沒有 馬上 Free 掉。 大概 要 15 分鐘 ?? 后 系統才 真正Free掉,這是系統 防止 短時間內 不斷 free 和 load。

uj5u.com熱心網友回復:

參考 9 樓 schlafenhamster 的回復:
我 記得 程式 FreeLibrary 后,系統 并沒有 馬上 Free 掉。 大概 要 15 分鐘 ?? 后 系統才 真正Free掉,這是系統 防止 短時間內 不斷 free 和 load。



多謝回答。

你的意思我大概明白,但是我的理解是:系統可能做了一個全域的緩沖區(姑且容我這么稱呼吧),對最近加載了的dll,運行過的程式等做快取,以加快再次運行同一程式或再次加載同一dll情況下的速度。這可能就是很多程式第一次運行比較慢,但是運行一次后可能會快一些。

但是以上這個假設,是系統做的,對于我們行程本身來說,我們什么都感覺不到。
也就是說,只要我free卸載了dll。行程空間中以前本來加載該dll的地址空間,就已經被廢棄,成為了無效的內容,不會再繼續是有效的可執行的代碼(即使這時候可能系統底層可能對該dll已經做了快取,但是我行程本身地址空間內一定是沒有的,而我行程的運行只能在我自己的地址空間,所以問題就出現了)。

uj5u.com熱心網友回復:

getprocess的之后,那個執行free好像 可以 判斷是否制定完畢,否則free掉就沒法呼叫了

uj5u.com熱心網友回復:

6666666666666666

uj5u.com熱心網友回復:

遍歷所有執行緒,除了卸載行程所有執行緒全部暫停,然后卸載執行緒先卸載HOOK,然后在恢復有所執行緒。

uj5u.com熱心網友回復:

遍歷所有執行緒,除了卸載執行緒之外的所有執行緒全部暫停,然后卸載執行緒先卸載HOOK,然后在恢復有所執行緒。

uj5u.com熱心網友回復:

learning~

uj5u.com熱心網友回復:

66666666666666

uj5u.com熱心網友回復:

參考 13 樓 void_main_void 的回復:
遍歷所有執行緒,除了卸載行程所有執行緒全部暫停,然后卸載執行緒先卸載HOOK,然后在恢復有所執行緒。


感謝回復。

你的想法和我覺得最理想的處理方式不謀而合!!!!
我的想法是:首先unhook所有我鉤了的函式。然后列舉所有執行緒,暫停,取該執行緒的呼叫堆疊。判斷呼叫堆疊里是否有我dll模塊所在的加載地址。如果沒有,那該執行緒沒問題。如果有就記錄該執行緒句柄。然后sleep一下后重復上面的判斷。直到確定所有執行緒的呼叫堆疊里,沒有我dll的呼叫。然后可以完全卸載dll。

這也是我想到最理想的方式。

但是,,,凡是都有但是。。。。

列舉執行緒,暫停執行緒,取堆疊等等系列操作,存在需要權限,會失敗等等問題。導致判斷流程有問題不在準確。一旦不能100%確保正確,那么也就意味著整個方案的失敗。

uj5u.com熱心網友回復:

dll detach的時候直接去掉回呼的函式不行嗎

uj5u.com熱心網友回復:

參考 18 樓 yfqvip 的回復:
dll detach的時候直接去掉回呼的函式不行嗎


這個操作是必須的,但是并不足夠,會存在我說的這個問題

uj5u.com熱心網友回復:

參考 19 樓 rageliu 的回復:
Quote: 參考 18 樓 yfqvip 的回復:

dll detach的時候直接去掉回呼的函式不行嗎


這個操作是必須的,但是并不足夠,會存在我說的這個問題

a.exe使用了b.dll注入
則在a要卸載b.dll時,如果fun_my正在被執行,則等待fun_my執行完畢后再卸載。
b.dll卸載時判斷fun是不是在呼叫fun_my,如果正在呼叫則等待呼叫完畢后將回呼置空。

uj5u.com熱心網友回復:

參考 20 樓 yfqvip 的回復:
Quote: 參考 19 樓 rageliu 的回復:

Quote: 參考 18 樓 yfqvip 的回復:

dll detach的時候直接去掉回呼的函式不行嗎


這個操作是必須的,但是并不足夠,會存在我說的這個問題

a.exe使用了b.dll注入
則在a要卸載b.dll時,如果fun_my正在被執行,則等待fun_my執行完畢后再卸載。
b.dll卸載時判斷fun是不是在呼叫fun_my,如果正在呼叫則等待呼叫完畢后將回呼置空。

我覺得這樣是可以解決問題的。如果這樣不能滿足你的要求,你可以考慮使用記憶體映射來實作呼叫,這樣就完全解耦了。

uj5u.com熱心網友回復:

參考 20 樓 yfqvip 的回復:
Quote: 參考 19 樓 rageliu 的回復:

Quote: 參考 18 樓 yfqvip 的回復:

dll detach的時候直接去掉回呼的函式不行嗎


這個操作是必須的,但是并不足夠,會存在我說的這個問題

a.exe使用了b.dll注入
則在a要卸載b.dll時,如果fun_my正在被執行,則等待fun_my執行完畢后再卸載。
b.dll卸載時判斷fun是不是在呼叫fun_my,如果正在呼叫則等待呼叫完畢后將回呼置空。



邏輯清晰明了,但是有個問題,怎么判斷是否正在呼叫fun_my??
這也是問題核心所在。。。

uj5u.com熱心網友回復:

參考 22 樓 rageliu 的回復:
Quote: 參考 20 樓 yfqvip 的回復:

Quote: 參考 19 樓 rageliu 的回復:

Quote: 參考 18 樓 yfqvip 的回復:

dll detach的時候直接去掉回呼的函式不行嗎


這個操作是必須的,但是并不足夠,會存在我說的這個問題

a.exe使用了b.dll注入
則在a要卸載b.dll時,如果fun_my正在被執行,則等待fun_my執行完畢后再卸載。
b.dll卸載時判斷fun是不是在呼叫fun_my,如果正在呼叫則等待呼叫完畢后將回呼置空。


邏輯清晰明了,但是有個問題,怎么判斷是否正在呼叫fun_my??
這也是問題核心所在。。。


設定一個標志就可以了,例如:

fun()
{)
{
if (flag) {
fun_my();
}
}

detach:
unload()
{
if (flag) {
flag = !flag;
int timeout_count = 8;
while (timeout_count -- > 0) {
 sleep(20); // or event.wait(20)
 if (!flag) {
    break;
 }
}
}

}

uj5u.com熱心網友回復:


bool is_call_ = false;
fun()
{
    if (flag) {
        is_call_ = true;
        fun_my();
        is_call_ = false;
    }
}


detach:
    unload()
    {
        if (flag) {
            flag = !flag;
            int timeout_count = 8;
            while (!is_call_ && timeout_count-- > 0) {
                sleep(20); // or event.wait(20)\
            }
        }

    }

uj5u.com熱心網友回復:

while (!is_call_改為while (is_call_

uj5u.com熱心網友回復:

參考 23 樓 yfqvip 的回復:
Quote: 參考 22 樓 rageliu 的回復:

Quote: 參考 20 樓 yfqvip 的回復:

Quote: 參考 19 樓 rageliu 的回復:

Quote: 參考 18 樓 yfqvip 的回復:

dll detach的時候直接去掉回呼的函式不行嗎


這個操作是必須的,但是并不足夠,會存在我說的這個問題

a.exe使用了b.dll注入
則在a要卸載b.dll時,如果fun_my正在被執行,則等待fun_my執行完畢后再卸載。
b.dll卸載時判斷fun是不是在呼叫fun_my,如果正在呼叫則等待呼叫完畢后將回呼置空。


邏輯清晰明了,但是有個問題,怎么判斷是否正在呼叫fun_my??
這也是問題核心所在。。。


設定一個標志就可以了,例如:

fun()
{)
{
if (flag) {
fun_my();
}
}

detach:
unload()
{
if (flag) {
flag = !flag;
int timeout_count = 8;
while (timeout_count -- > 0) {
 sleep(20); // or event.wait(20)
 if (!flag) {
    break;
 }
}
}

}


首先感謝你的回復。

你的意思我明白,說下我的理解。
一個函式的呼叫,存在呼叫堆疊的保存,壓參等操作。也就是說。并不是c++代碼看到的第一行就是匯編代碼的第一行,前面還有很多行匯編代碼的(這里不討論直接內嵌匯編的特殊情況)。所以,假設一種運行狀態為:

呼叫進入我fun_my,正在壓參,注意這時候已經進入了函式,但是卻又還沒有設定我們希望看到的標志量。既然沒有設定標志量,那我就認為已經不呼叫了,卸載了dll。但實際情況卻是正在呼叫。

當然我們可以在多等待一段時間,而且我目前也確實是這么做的。但是這個等待的時間不好確定,肯定是越長越好。能解決,但不優雅。

uj5u.com熱心網友回復:

參考 26 樓 rageliu 的回復:
Quote: 參考 23 樓 yfqvip 的回復:

Quote: 參考 22 樓 rageliu 的回復:

Quote: 參考 20 樓 yfqvip 的回復:

Quote: 參考 19 樓 rageliu 的回復:

Quote: 參考 18 樓 yfqvip 的回復:

dll detach的時候直接去掉回呼的函式不行嗎


這個操作是必須的,但是并不足夠,會存在我說的這個問題

a.exe使用了b.dll注入
則在a要卸載b.dll時,如果fun_my正在被執行,則等待fun_my執行完畢后再卸載。
b.dll卸載時判斷fun是不是在呼叫fun_my,如果正在呼叫則等待呼叫完畢后將回呼置空。


邏輯清晰明了,但是有個問題,怎么判斷是否正在呼叫fun_my??
這也是問題核心所在。。。


設定一個標志就可以了,例如:

fun()
{)
{
if (flag) {
fun_my();
}
}

detach:
unload()
{
if (flag) {
flag = !flag;
int timeout_count = 8;
while (timeout_count -- > 0) {
 sleep(20); // or event.wait(20)
 if (!flag) {
    break;
 }
}
}

}


首先感謝你的回復。

你的意思我明白,說下我的理解。
一個函式的呼叫,存在呼叫堆疊的保存,壓參等操作。也就是說。并不是c++代碼看到的第一行就是匯編代碼的第一行,前面還有很多行匯編代碼的(這里不討論直接內嵌匯編的特殊情況)。所以,假設一種運行狀態為:

呼叫進入我fun_my,正在壓參,注意這時候已經進入了函式,但是卻又還沒有設定我們希望看到的標志量。既然沒有設定標志量,那我就認為已經不呼叫了,卸載了dll。但實際情況卻是正在呼叫。

當然我們可以在多等待一段時間,而且我目前也確實是這么做的。但是這個等待的時間不好確定,肯定是越長越好。能解決,但不優雅。

如果是單執行緒的,用24#貼的代碼不存在你說的這種情況的;如果是多執行緒的在這個代碼上加個鎖就行了。

uj5u.com熱心網友回復:

也就是說,這個設定標志量的方式,能有一定的作用,如果為true,說明一定在呼叫,不能卸載。但是如果為false。卻不能保證沒有呼叫。

uj5u.com熱心網友回復:

fun_my函式的呼叫執行緒,和dll的卸載執行緒。怎么可能在同一條執行緒呢,自己呼叫來卸載自己所在的dll?

uj5u.com熱心網友回復:

參考 28 樓 rageliu 的回復:
也就是說,這個設定標志量的方式,能有一定的作用,如果為true,說明一定在呼叫,不能卸載。但是如果為false。卻不能保證沒有呼叫。

我覺得你想多了,試試就知道了。

uj5u.com熱心網友回復:

參考 29 樓 rageliu 的回復:
fun_my函式的呼叫執行緒,和dll的卸載執行緒。怎么可能在同一條執行緒呢,自己呼叫來卸載自己所在的dll?

那加個鎖就可以啦。

uj5u.com熱心網友回復:

至于加鎖,和我上面說的同一個道理,函式的呼叫原理。

uj5u.com熱心網友回復:

加鎖,連while回圈判斷都省了

uj5u.com熱心網友回復:

參考 30 樓 yfqvip 的回復:
Quote: 參考 28 樓 rageliu 的回復:

也就是說,這個設定標志量的方式,能有一定的作用,如果為true,說明一定在呼叫,不能卸載。但是如果為false。卻不能保證沒有呼叫。

我覺得你想多了,試試就知道了。


兄臺,我提出來這個問題,我肯定是除錯過的。
另外,你可以除錯下函式的呼叫程序,顯示匯編代碼看看。你就會明白我的意思。

uj5u.com熱心網友回復:

參考 32 樓 rageliu 的回復:
至于加鎖,和我上面說的同一個道理,函式的呼叫原理。

你想多了,加鎖后,fun沒呼叫完detach會被阻塞的。

uj5u.com熱心網友回復:

參考 33 樓 yfqvip 的回復:
加鎖,連while回圈判斷都省了


那恕我直言,你對鎖的理解不對,或者說不完整。

既然你鎖能鎖住,那就一定進代碼了,也就一定進入了函式。如果你覺得沒進入函式,那又是怎么鎖住的呢?

uj5u.com熱心網友回復:

參考 35 樓 yfqvip 的回復:
Quote: 參考 32 樓 rageliu 的回復:

至于加鎖,和我上面說的同一個道理,函式的呼叫原理。

你想多了,加鎖后,fun沒呼叫完detach會被阻塞的。


按你的說法,我們假設現在detach拿到了鎖。你認為fun_my就不能執行了么???

請注意,這里只是fun_my拿不到鎖,并不是不能執行?

拿不到 和不能執行。。。完全2個概念

uj5u.com熱心網友回復:


fun()
{
    auto_lock;
    if (flag) {
        fun_my();
    }
}


detach:
unload()
{
    auto_lock;
    if (flag) {
        flag = !flag;
    }
}

這樣應該沒有問題呀,無論怎么進鎖,只要detach了都不會再調到fun_my了呀。

uj5u.com熱心網友回復:

總共兩種情況:
1、detach時fun已經進入鎖了,則detach等待fun呼叫完成后執行,fun再次被呼叫時無法呼叫fun_my
2、detach時fun正在等待進入鎖,則detach執行完畢后fun進入鎖,發現flagbei

uj5u.com熱心網友回復:

總共兩種情況:
1、detach時fun已經進入鎖了,則detach等待fun呼叫完成后執行,fun再次被呼叫時無法呼叫fun_my
2、detach時fun正在等待進入鎖,則detach執行完畢后fun進入鎖,發現flag被設定為false,則不會呼叫fun_my

uj5u.com熱心網友回復:

假設detach拿到了鎖,你認為 fun_my就會被鎖住。那問題來了,請問fun_my為什么會被鎖住,答案肯定是因為它試圖去拿鎖而不得。。。。注意,既然它試圖去拿鎖,試圖去做一件事情。是不是恰恰說明它已經在執行某些代碼了????

uj5u.com熱心網友回復:

參考 40 樓 yfqvip 的回復:
總共兩種情況:
1、detach時fun已經進入鎖了,則detach等待fun呼叫完成后執行,fun再次被呼叫時無法呼叫fun_my
2、detach時fun正在等待進入鎖,則detach執行完畢后fun進入鎖,發現flag被設定為false,則不會呼叫fun_my



這里你理解錯誤。。。并不是“無法呼叫fun_my” 。。。二是能呼叫,只是拿不到鎖。前面我已經說了,這是2個不同的概念。。

uj5u.com熱心網友回復:

關鍵你一定要理解到,不是不能呼叫,而是能呼叫,代碼能執行,只是要等鎖。

uj5u.com熱心網友回復:

參考 41 樓 rageliu 的回復:
假設detach拿到了鎖,你認為 fun_my就會被鎖住。那問題來了,請問fun_my為什么會被鎖住,答案肯定是因為它試圖去拿鎖而不得。。。。注意,既然它試圖去拿鎖,試圖去做一件事情。是不是恰恰說明它已經在執行某些代碼了????


參考 42 樓 rageliu 的回復:
Quote: 參考 40 樓 yfqvip 的回復:

總共兩種情況:
1、detach時fun已經進入鎖了,則detach等待fun呼叫完成后執行,fun再次被呼叫時無法呼叫fun_my
2、detach時fun正在等待進入鎖,則detach執行完畢后fun進入鎖,發現flag被設定為false,則不會呼叫fun_my



這里你理解錯誤。。。并不是“無法呼叫fun_my” 。。。二是能呼叫,只是拿不到鎖。前面我已經說了,這是2個不同的概念。。

先別著急哈,我們慢慢看這段代碼:
fun()
{
    auto_lock;
    if (flag) {
        fun_my();
    }
}
 
 
detach:
unload()
{
    auto_lock;
    if (flag) {
        flag =false;
    }
}

fun在等待進入鎖的時候unload已經將flag設定為false了,所以fun進入鎖后無法呼叫到fun_my

uj5u.com熱心網友回復:

或這么說,會比較好理解,既然鎖是在函式內部的區域變數,是不是就只能內部有效。既然內部有效,首先肯定要執行到函式內部啊 。

uj5u.com熱心網友回復:

老大,冷靜。。。。
fun是原始函式,你不能修改,唯一能修改的是fun_my啊。。。。。

uj5u.com熱心網友回復:

你直接貼一下你的原始碼吧,從原始碼上講可能不容易有誤解

uj5u.com熱心網友回復:

哈哈,假設這里說的fun就是系統API:MessageBox
我就是為了注入別人的程式,去攔截這個呼叫到我的 MessageBox_My。
就這個意思。

uj5u.com熱心網友回復:

參考 48 樓 rageliu 的回復:
哈哈,假設這里說的fun就是系統API:MessageBox
我就是為了注入別人的程式,去攔截這個呼叫到我的 MessageBox_My。
就這個意思。

哦,明白了。
在DLL_PROCESS_ATTACH的時候intall,在DLL_PROCESS_DETACH的時候uninstall;
則,在install時注入需要執行的函式,同時保存源函式指標;
在uninstall的時候講保存的源函式指標反注冊回去。
我在某個商用軟體里就是這么干的,用戶量也有幾十萬吧,好像沒有收到說的這種問題的反饋報告。

uj5u.com熱心網友回復:

其實你的思路我明白,

參考 49 樓 yfqvip 的回復:
Quote: 參考 48 樓 rageliu 的回復:

哈哈,假設這里說的fun就是系統API:MessageBox
我就是為了注入別人的程式,去攔截這個呼叫到我的 MessageBox_My。
就這個意思。

哦,明白了。
在DLL_PROCESS_ATTACH的時候intall,在DLL_PROCESS_DETACH的時候uninstall;
則,在install時注入需要執行的函式,同時保存源函式指標;
在uninstall的時候講保存的源函式指標反注冊回去。
我在某個商用軟體里就是這么干的,用戶量也有幾十萬吧,好像沒有收到說的這種問題的反饋報告。



那我們假設一種情況:正在執行fun_my。這時候關閉你的軟體,你注入的dll會被卸載么?如果卸載,那正在執行的fun_my又恰好在你的dll模塊代碼里,這時候就崩潰了啊。因為執行代碼所在的模塊都被卸載沒有了。。

uj5u.com熱心網友回復:

不會的,freelibrary時作業系統應該會等待你的函式呼叫完成,如果超過一定時間沒有呼叫完成才會出現崩潰,所以盡量保證你注入的函式不要阻塞就可以了。如果實在不放心的話在反注冊后等待幾十毫秒就可以了。

uj5u.com熱心網友回復:

參考 51 樓 yfqvip 的回復:
不會的,freelibrary時作業系統應該會等待你的函式呼叫完成,如果超過一定時間沒有呼叫完成才會出現崩潰,所以盡量保證你注入的函式不要阻塞就可以了。如果實在不放心的話在反注冊后等待幾十毫秒就可以了。


朋友你想多了

uj5u.com熱心網友回復:

參考 52 樓 rageliu 的回復:
Quote: 參考 51 樓 yfqvip 的回復:

不會的,freelibrary時作業系統應該會等待你的函式呼叫完成,如果超過一定時間沒有呼叫完成才會出現崩潰,所以盡量保證你注入的函式不要阻塞就可以了。如果實在不放心的話在反注冊后等待幾十毫秒就可以了。


朋友你想多了

我覺得還是你哪個細節上的處理有問題,正常來講不應該出現你說的這個問題的。你看看下面這段代碼對你有沒有幫助。


bool xxx::RemoteLoadLibrary(HANDLE hProcess, LPCTSTR lpPathDLL)
{
bool ret = false;
HMODULE hKernel32 = GetModuleHandle(_T("Kernel32"));
if (hKernel32)
{
FARPROC pfnThreadRtn = GetProcAddress(hKernel32, "LoadLibraryW");
if (pfnThreadRtn)
{
LPVOID pParaRtn = VirtualAllocEx(hProcess, NULL, MAX_PATH, MEM_COMMIT, PAGE_READWRITE);
if (pParaRtn)
{
DWORD iLen = wcslen(lpPathDLL) * sizeof(wchar_t)+2;
DWORD dwWritten = 0;
if (WriteProcessMemory(hProcess, pParaRtn, lpPathDLL, iLen, &dwWritten))
{
if (dwWritten == iLen)
{
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pfnThreadRtn, pParaRtn, 0, NULL);
if (hThread != INVALID_HANDLE_VALUE)
{
WaitForSingleObject(hThread, 3000);
CloseHandle(hThread);
ret = true;
}
}
}
VirtualFreeEx(hProcess, pParaRtn, 0, MEM_RELEASE);
}
}
}
return ret;
}

bool xxx::RemoteFreeLibrary(LPCTSTR lpPathDLL, HANDLE hProcess)
{
bool ret = false;
HANDLE hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(hProcess));
if (INVALID_HANDLE_VALUE != hModuleSnap)
{
MODULEENTRY32 me32;
memset(&me32, 0, sizeof(MODULEENTRY32));
me32.dwSize = sizeof(MODULEENTRY32);
bool bFound = false;
BOOL bOK = ::Module32First(hModuleSnap, &me32);
while (bOK)
{
bFound = (0 == ::_tcsicmp(me32.szModule, lpPathDLL) || 0 == ::_tcsicmp(me32.szExePath, lpPathDLL));
if (bFound)
{
break;
}
bOK = ::Module32Next(hModuleSnap, &me32);
}
if (bFound)
{
LPTHREAD_START_ROUTINE lpThreadFun = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "FreeLibrary");
if (lpThreadFun)
{
HANDLE hThread = ::CreateRemoteThread(hProcess, NULL, 0, lpThreadFun, me32.modBaseAddr /* 模塊地址 */, 0, NULL);
if (hThread)
{
::WaitForSingleObject(hThread, 200);
::CloseHandle(hThread);
ret = true;
}
}
}
::CloseHandle(hModuleSnap);
}
return ret;
}

uj5u.com熱心網友回復:

首先感謝你的代碼,遠程執行緒注入也有用到。
關于我說到的這個問題,不是代碼問題,理論想清楚,這個問題是一定存在的。
就像你說的,多等待一會,也就是為了防這個問題。
而且和函式的執行時間長短,呼叫頻率等都有關系,所以是概率的。但是一定存在。

uj5u.com熱心網友回復:

EnterCriticalSection( &m_cs );
FreeLibrary(hModule);
LeaveCriticalSection(&CriticalSection);

dll 中 函式 先
EnterCriticalSection( &m_cs );

uj5u.com熱心網友回復:

參考 55 樓 schlafenhamster 的回復:
EnterCriticalSection( &m_cs );
FreeLibrary(hModule);
LeaveCriticalSection(&CriticalSection);

dll 中 函式 先
EnterCriticalSection( &m_cs );


大哥,函式的呼叫理解不對,你這樣用鎖或臨界的方式是不對的。前面我解釋過這個問題。

uj5u.com熱心網友回復:

這么說吧,鎖或臨界,都是對它后面的起作用,位于它前面的,它根本管不了。前面部分的代碼照常執行。。。

uj5u.com熱心網友回復:

不要說這是函式的第一行。函式的呼叫方式,前面還有很多匯編代碼的。執行到臨界的時候,早已經進入了函式了。

uj5u.com熱心網友回復:

參考 54 樓 rageliu 的回復:
首先感謝你的代碼,遠程執行緒注入也有用到。
關于我說到的這個問題,不是代碼問題,理論想清楚,這個問題是一定存在的。
就像你說的,多等待一會,也就是為了防這個問題。
而且和函式的執行時間長短,呼叫頻率等都有關系,所以是概率的。但是一定存在。

如果只是理論上的話,也許你想像中的理論存在你不知道的機制。可以從呼叫的結果上做出反推。
我注入的那個dll中的函式一秒鐘會呼叫幾十次以上的,而且是一直呼叫,沒出現你說的這個問題。
卸載時呼叫CreateRemoteThread有時候會被阻塞一段時間,我推測它可能在進行一些清理的作業。
這是一個比較常見的場景,如果這種場景都會出現崩潰,官方設計的這個機制就顯得太脆弱了。

uj5u.com熱心網友回復:

《Windows核心編程》

uj5u.com熱心網友回復:

參考 59 樓 yfqvip 的回復:
Quote: 參考 54 樓 rageliu 的回復:

首先感謝你的代碼,遠程執行緒注入也有用到。
關于我說到的這個問題,不是代碼問題,理論想清楚,這個問題是一定存在的。
就像你說的,多等待一會,也就是為了防這個問題。
而且和函式的執行時間長短,呼叫頻率等都有關系,所以是概率的。但是一定存在。

如果只是理論上的話,也許你想像中的理論存在你不知道的機制。可以從呼叫的結果上做出反推。
我注入的那個dll中的函式一秒鐘會呼叫幾十次以上的,而且是一直呼叫,沒出現你說的這個問題。
卸載時呼叫CreateRemoteThread有時候會被阻塞一段時間,我推測它可能在進行一些清理的作業。
這是一個比較常見的場景,如果這種場景都會出現崩潰,官方設計的這個機制就顯得太脆弱了。


我實際測驗過的,構建個環境就能知道了。

uj5u.com熱心網友回復:

執行到臨界的時候,還沒有進入 FreeLibrary(hModule); !

uj5u.com熱心網友回復:

參考 50 樓 rageliu 的回復:
那我們假設一種情況:正在執行fun_my。這時候關閉你的軟體,你注入的dll會被卸載么?如果卸載,那正在執行的fun_my又恰好在你的dll模塊代碼里,這時候就崩潰了啊。因為執行代碼所在的模塊都被卸載沒有了。。

我試了下,在DLL中case DLL_PROCESS_DETACH里加了Sleep(10000)延時10秒,
程式呼叫UnhookWindowsHookEx(hHook);卸載HOOK,DLL還是要等DLL_PROCESS_DETACH中的代碼執行完才會從行程中卸載,
說明不是一呼叫UnhookWindowsHookEx(hHook)或FreeLibrary(),DLL就會馬上從行程中卸載

uj5u.com熱心網友回復:

"在DLL中case DLL_PROCESS_DETACH里加了Sleep(10000)延時10秒,"
可行

uj5u.com熱心網友回復:

參考 63 樓 zwfgdlc 的回復:
Quote: 參考 50 樓 rageliu 的回復:

那我們假設一種情況:正在執行fun_my。這時候關閉你的軟體,你注入的dll會被卸載么?如果卸載,那正在執行的fun_my又恰好在你的dll模塊代碼里,這時候就崩潰了啊。因為執行代碼所在的模塊都被卸載沒有了。。

我試了下,在DLL中case DLL_PROCESS_DETACH里加了Sleep(10000)延時10秒,
程式呼叫UnhookWindowsHookEx(hHook);卸載HOOK,DLL還是要等DLL_PROCESS_DETACH中的代碼執行完才會從行程中卸載,
說明不是一呼叫UnhookWindowsHookEx(hHook)或FreeLibrary(),DLL就會馬上從行程中卸載


DLL_PROCESS_DETACH里的代碼,當然會執行。

uj5u.com熱心網友回復:

我又特地試了下,似乎沒有出現你所的那種現象.
DLL代碼:

LPVOID pfnMessageBox = 0;

int WINAPI HookMessageBox(
_In_opt_  HWND hWnd,
_In_opt_  LPCTSTR lpText,
_In_opt_  LPCTSTR lpCaption,
_In_      UINT uType)
{
LPTSTR Text = TEXT("Hook!!!");
int a = 0;
do
{
a++;
Sleep(2000);

} while (a < 5); //等待10秒

__asm
{
push uType
push lpCaption
push Text
push hWnd
call dword ptr pfnMessageBox
}
}

BOOL WINAPI DllMain(
HINSTANCE hinstDLL,  // handle to DLL module
DWORD fdwReason,     // reason for calling function
LPVOID lpReserved)  // reserved
{
// Perform actions based on the reason for calling.
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
hDll = hinstDLL;
GetModuleFileName(NULL, szModuleFileName, _countof(szModuleFileName));

if (_tcsicmp(PathFindFileName(szModuleFileName), TEXT("Hash.exe")) == 0)
{
pfnMessageBox = HookApi(TEXT("user32.dll"), "MessageBoxW", HookMessageBox, 5); //inline Hook,函式頭部寫入E9 xxxx方式
MessageBox(NULL, TEXT("123456"), NULL, MB_ICONASTERISK);
}

break;

case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;

case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;

case DLL_PROCESS_DETACH:
/*if (_tcsicmp(PathFindFileName(szModuleFileName), TEXT("Hash.exe")) == 0)
{
OutputDebugString(L"Hash.exe DLL_PROCESS_DETACH Start!!!!\n");
Sleep(10000);
OutputDebugString(L"Hash.exe DLL_PROCESS_DETACH End!!!!\n");
}*/
// Perform any necessary cleanup.
break;
}
return TRUE;  // Successful DLL_PROCESS_ATTACH.
}


LRESULT CALLBACK GetMsgProc(
_In_  int code,
_In_  WPARAM wParam,
_In_  LPARAM lParam)
{
return CallNextHookEx(hHook, code, wParam, lParam);
}


int SetHook()
{
hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hDll, 0);
return 1;
}

int UnSetHook()
{
UnhookWindowsHookEx(hHook);
return 1;
}

EXE代碼:

int WINAPI _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd)
{
HMODULE hDll = LoadLibrary(TEXT("MsgHook.dll"));
if (hDll)
{
PROC Hook = GetProcAddress(hDll, "SetHook");
PROC UnHook = GetProcAddress(hDll, "UnSetHook");
Hook();

Sleep(5000);
UnHook();
}
return 0;
}

uj5u.com熱心網友回復:

在uninstall的時候講保存的源函式指標反注冊回去

uj5u.com熱心網友回復:

直到程式結束,不卸載DLL了不可以嗎?

uj5u.com熱心網友回復:

參考 17 樓 rageliu 的回復:
Quote: 參考 13 樓 void_main_void 的回復:

遍歷所有執行緒,除了卸載行程所有執行緒全部暫停,然后卸載執行緒先卸載HOOK,然后在恢復有所執行緒。


感謝回復。

你的想法和我覺得最理想的處理方式不謀而合!!!!
我的想法是:首先unhook所有我鉤了的函式。然后列舉所有執行緒,暫停,取該執行緒的呼叫堆疊。判斷呼叫堆疊里是否有我dll模塊所在的加載地址。如果沒有,那該執行緒沒問題。如果有就記錄該執行緒句柄。然后sleep一下后重復上面的判斷。直到確定所有執行緒的呼叫堆疊里,沒有我dll的呼叫。然后可以完全卸載dll。

這也是我想到最理想的方式。

但是,,,凡是都有但是。。。。

列舉執行緒,暫停執行緒,取堆疊等等系列操作,存在需要權限,會失敗等等問題。導致判斷流程有問題不在準確。一旦不能100%確保正確,那么也就意味著整個方案的失敗。


去參考微軟的 Detours 原始碼。

uj5u.com熱心網友回復:

參考 64 樓 schlafenhamster 的回復:
"在DLL中case DLL_PROCESS_DETACH里加了Sleep(10000)延時10秒,"
可行


為什么可行,那我假設fun_my里有個運算,耗時11秒。怎么辦?

只是假設出問題的情況。當然10秒了,肯定

參考 69 樓 void_main_void 的回復:
Quote: 參考 17 樓 rageliu 的回復:

Quote: 參考 13 樓 void_main_void 的回復:

遍歷所有執行緒,除了卸載行程所有執行緒全部暫停,然后卸載執行緒先卸載HOOK,然后在恢復有所執行緒。


感謝回復。

你的想法和我覺得最理想的處理方式不謀而合!!!!
我的想法是:首先unhook所有我鉤了的函式。然后列舉所有執行緒,暫停,取該執行緒的呼叫堆疊。判斷呼叫堆疊里是否有我dll模塊所在的加載地址。如果沒有,那該執行緒沒問題。如果有就記錄該執行緒句柄。然后sleep一下后重復上面的判斷。直到確定所有執行緒的呼叫堆疊里,沒有我dll的呼叫。然后可以完全卸載dll。

這也是我想到最理想的方式。

但是,,,凡是都有但是。。。。

列舉執行緒,暫停執行緒,取堆疊等等系列操作,存在需要權限,會失敗等等問題。導致判斷流程有問題不在準確。一旦不能100%確保正確,那么也就意味著整個方案的失敗。


去參考微軟的 Detours 原始碼。


肯定的告訴你,它是有這個問題的。當然我用的是免費版,不確定付費版是否有解決,畢竟1萬刀,付不起。

uj5u.com熱心網友回復:

to zwfgdlc:

附加到目標行程除錯。
斷case DLL_PROCESS_DETACH:和__asm。
看看到detach的時候,上面回圈是否執行完成。

uj5u.com熱心網友回復:

to zwfgdlc:

你這個測驗的代碼貌似不對。
將呼叫放在DLL_PROCESS_ATTACH里是不行的。

因為attach和detach肯定是串行的啊。這么寫就不會有多執行緒環境了。

uj5u.com熱心網友回復:

參考 72 樓 rageliu 的回復:
to zwfgdlc:

你這個測驗的代碼貌似不對。
將呼叫放在DLL_PROCESS_ATTACH里是不行的。

因為attach和detach肯定是串行的啊。這么寫就不會有多執行緒環境了。

你仔細看下我代碼中的邏輯,
當EXE執行UnHook()時,被注入的行程正在執行DLL領空HookMessageBox()函式中的do...while回圈代碼,
不正是你所說的那樣"但是在我要卸載鉤子的時候,如果剛好代碼執行在我的函式Fun_My的代碼里。就會崩潰。"

uj5u.com熱心網友回復:

我明白你的意思。但是你不覺得比較怪么。

Hook();
Sleep(5000);
UnHook();

這里的Hook() 會安裝鉤子,安裝鉤子是不是會注入dll。那么dll里的attach會不會同步執行完畢呢?如果會。那attach里對messagebox的呼叫,會不會已經執行了??

你測驗的時候,確定UnHook()都執行了,attach呼叫過去的messagebox卻正在執行?

uj5u.com熱心網友回復:

也就是detach都只新完畢了,attach的呼叫卻正在執行???

怎么感覺就很怪呢

關鍵就是對messagebox的呼叫,并不是注入行程其他地方呼叫過來的,而是你在attach呼叫的。。。

uj5u.com熱心網友回復:

我嘗試解釋下你測驗為什么不出問題。
按我的理解,attach一定會先于detach呼叫完畢。它們一定是會串行呼叫。所以你在attach里的呼叫。永遠會在detach后面。所以不出問題

uj5u.com熱心網友回復:

我確定是UnHook()都執行了,并且我的EXE行程都已經退出了,被注入的行程還在執行回圈代碼,最后MessageBox彈出后,DLL才從行程中卸載

uj5u.com熱心網友回復:

參考 77 樓 zwfgdlc 的回復:
我確定是UnHook()都執行了,并且我的EXE行程都已經退出了,被注入的行程還在執行回圈代碼,最后MessageBox彈出后,DLL才從行程中卸載


老大,你怎么就沒明白呢。這個流程不就對了嗎。。
這是因為你代碼有問題,把messagebox的呼叫放到了attach。被你自己強行寫成串行執行了。

如果messagebox的呼叫來自程式其他地方,不來自attach。注意是不來自attach!!!!!就有問題了阿。

uj5u.com熱心網友回復:

 //inline Hook,函式頭部寫入E9 xxxx方式
pfnMessageBox = HookApi(TEXT("user32.dll"), "MessageBoxW", HookMessageBox, 5);
我是先HOOK了MessageBox再呼叫MessageBox,既然已經HOOK了,呼叫MessageBox肯定是會跳轉到DLL中HookMessageBox函式,然后在那執行回圈延時10秒.
MessageBox(NULL, TEXT("123456"), NULL, MB_ICONASTERISK);

uj5u.com熱心網友回復:

這是因為你代碼有問題,把messagebox的呼叫放到了attach。被你自己強行寫成串行執行了。
如果messagebox的呼叫來自程式其他地方,不來自attach。注意是不來自attach!!!!!就有問題了阿

把messagebox的呼叫放到了attach。被你自己強行寫成串行執行了。
把messagebox的呼叫放到了attach。被你自己強行寫成串行執行了。
把messagebox的呼叫放到了attach。被你自己強行寫成串行執行了。
把messagebox的呼叫放到了attach。被你自己強行寫成串行執行了。

如果messagebox的呼叫來自程式其他地方,不來自attach。注意是不來自attach!!!!!就有問題了阿
如果messagebox的呼叫來自程式其他地方,不來自attach。注意是不來自attach!!!!!就有問題了阿
如果messagebox的呼叫來自程式其他地方,不來自attach。注意是不來自attach!!!!!就有問題了阿
如果messagebox的呼叫來自程式其他地方,不來自attach。注意是不來自attach!!!!!就有問題了阿

uj5u.com熱心網友回復:

不用糾結是否先hook。

注意我說的好么,呼叫來自attach就不對。。。。
注意我說的好么,呼叫來自attach就不對。。。。
注意我說的好么,呼叫來自attach就不對。。。。
注意我說的好么,呼叫來自attach就不對。。。。

uj5u.com熱心網友回復:

參考 81 樓 rageliu 的回復:
不用糾結是否先hook。

注意我說的好么,呼叫來自attach就不對。。。。
注意我說的好么,呼叫來自attach就不對。。。。
注意我說的好么,呼叫來自attach就不對。。。。
注意我說的好么,呼叫來自attach就不對。。。。

明白,看來我想得太簡單了

uj5u.com熱心網友回復:

因為attach和detach一定是串行的。或是理解為它們一定在同一個執行緒。代碼在它們之間,肯定會被串行話。

呼叫如果來自其他地方,也就是其他執行緒,這樣就不在它們的執行緒里。才會出問題。。

uj5u.com熱心網友回復:

將卸載執行緒和呼叫執行緒hook在同一個執行緒就OK了

uj5u.com熱心網友回復:

在被hook的行程下申請兩段記憶體,hook時先跳轉到第一段記憶體,然后再跳轉到dll中的代碼執行,然后再跳轉到第二段記憶體執行。
第一段記憶體的代碼主要是加鎖,判斷dll是否被卸載,如果被卸載,就跳轉到原被hook的函式處,然后再跳轉到第二段記憶體;否則直接跳轉到dll的代碼執行。
第二段記憶體的代碼就是解鎖。
dll卸載時,加鎖,設定卸載標記,卸載。
申請的兩段記憶體不用釋放。

轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/122911.html

標籤:基礎類

上一篇:vs2008 MFC serialport類的ModBus上位機通訊程式發送時埠例外關閉問題

下一篇:怎么讀取網線中的 12(發)、45(收)的資料流,不是抓包

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • Git本地庫既關聯GitHub又關聯Gitee

    創建代碼倉庫 使用gitee舉例(github和gitee差不多) 1.在gitee右上角點擊+,選擇新建倉庫 ? 2.選擇填寫倉庫資訊,然后進行創建 ? 3.服務端已經準備好了,本地開始作準備 (1)Git 全域設定 git config --global user.name "成鈺" git c ......

    uj5u.com 2020-09-10 05:04:14 more
  • CODING DevOps 代碼質量實戰系列第二課,相約周三

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。**《DevOps 代碼質量實戰(PHP 版)》**為 CODING DevOps 代碼質量實戰系列的第二課,同時也是本系列的 PHP ......

    uj5u.com 2020-09-10 05:07:43 more
  • 推薦Scrum書籍

    推薦Scrum書籍 直接上干貨,推薦書籍清單如下(推薦有順序的哦) Scrum指南 Scrum精髓 Scrum敏捷軟體開發 Scrum捷徑 硝煙中的Scrum和XP : 我們如何實施Scrum 敏捷軟體開發:Scrum實戰指南 Scrum要素 大規模Scrum:大規模敏捷組織的設計 用戶故事地圖 用 ......

    uj5u.com 2020-09-10 05:07:45 more
  • CODING DevOps 代碼質量實戰系列最后一課,周四發車

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。 **《DevOps 代碼質量實戰(Java 版)》**為 CODING DevOps 代碼質量實戰系列的最后一課,同時也是本系列的 ......

    uj5u.com 2020-09-10 05:07:52 more
  • 敏捷軟體工程實踐書籍

    Scrum轉型想要做好,第一步先了解并真正落實Scrum,那么我推薦的Scrum書籍是要看懂并實踐的。第二步是團隊的工程實踐要做扎實。 下面推薦工程實踐書單: 重構:改善既有代碼的設計 決議極限編程 : 擁抱變化 代碼整潔代碼 程式員的職業素養 修改代碼的藝術 撰寫可讀代碼的藝術 測驗驅動開發 : ......

    uj5u.com 2020-09-10 05:07:55 more
  • Jenkins+svn+nginx實作windows環境自動部署vue前端專案

    前面文章介紹了Jenkins+svn+tomcat實作自動化部署,現在終于有空抽時間出來寫下Jenkins+svn+nginx實作自動部署vue前端專案。 jenkins的安裝和配置已經在前面文章進行介紹,下面介紹實作vue前端專案需要進行的哪些額外的步驟。 注意:在安裝jenkins和nginx的 ......

    uj5u.com 2020-09-10 05:08:49 more
  • CODING DevOps 微服務專案實戰系列第一課,明天等你

    CODING DevOps 微服務專案實戰系列第一課**《DevOps 微服務專案實戰:DevOps 初體驗》**將由 CODING DevOps 開發工程師 王寬老師 向大家介紹 DevOps 的基本理念,并探討為什么現代開發活動需要 DevOps,同時將以 eShopOnContainers 項 ......

    uj5u.com 2020-09-10 05:09:14 more
  • CODING DevOps 微服務專案實戰系列第二課來啦!

    近年來,工程專案的結構越來越復雜,需要接入合適的持續集成流水線形式,才能滿足更多變的需求,那么如何優雅地使用 CI 能力提升生產效率呢?CODING DevOps 微服務專案實戰系列第二課 《DevOps 微服務專案實戰:CI 進階用法》 將由 CODING DevOps 全堆疊工程師 何晨哲老師 向 ......

    uj5u.com 2020-09-10 05:09:33 more
  • CODING DevOps 微服務專案實戰系列最后一課,周四開講!

    隨著軟體工程越來越復雜化,如何在 Kubernetes 集群進行灰度發布成為了生產部署的”必修課“,而如何實作安全可控、自動化的灰度發布也成為了持續部署重點關注的問題。CODING DevOps 微服務專案實戰系列最后一課:**《DevOps 微服務專案實戰:基于 Nginx-ingress 的自動 ......

    uj5u.com 2020-09-10 05:10:00 more
  • CODING 儀表盤功能正式推出,實作作業資料可視化!

    CODING 儀表盤功能現已正式推出!該功能旨在用一張張統計卡片的形式,統計并展示使用 CODING 中所產生的資料。這意味著無需額外的設定,就可以收集歸納寶貴的作業資料并予之量化分析。這些海量的資料皆會以圖表或串列的方式躍然紙上,方便團隊成員隨時查看各專案的進度、狀態和指標,云端協作迎來真正意義上 ......

    uj5u.com 2020-09-10 05:11:01 more
最新发布
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:41:12 more
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:35:34 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:05:44 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:00:18 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:20:31 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:55 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:18:51 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:00 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:17:55 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:12:06 more